JDBC

JDBC

持久化和持久化技术


  • 持久化技术
    • 概念

把数据保存到可掉电式的存储设备中,持久化的实现过程大多是通过各种关系数据库完成的

  • Java访问数据库的两种方式
    • 直接使用JDBCAPI去访问数据库(mysql/Oracle)
    • 间接地使用JDBCAPI去访问数据库服务器,如HibernateMyBatis
  • JDBC的作用

为访问不同的数据库提供了统一的途径,为开发者屏蔽了一些细节问题。

获取数据库连接


  • 获取连接对象的步骤

记得导入相应的驱动包:mysql-connecttor-java-5.1.26-bin.jar

步骤:
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest", "root", "root");

JDBC中常用的API


  • JDBC操作步骤
    • 加载注册驱动
    • 获取连接对象
    • 创建语句对象
    • 执行sql
    • 释放资源(一定要记得关闭资源)

DML操作


对数据库的表进行增加删除修改操作

DQL操作


对数据库的表进行查询操作

DAO的设计思想


  • 概念

DAO(Data Access Object)是一个数据访问接口,数据访问:与数据库打交道。夹在业务逻辑(Service)与数据库资源中间。

  • DAO实现的规范
    • DAO的命名
  com.ghyz.ppd.dao         -- 定义DAO的接口
  com.ghyz.ppd.dao.impl    -- 定义DAO的接口实现类
  com.ghyz.ppd.test        -- 定义测试类
  com.ghyz.ppd.util        -- 定义实体类
  
  // 接口和实现类的规范
  DAO的接口:IXxxDAO,IXxxDao
  DAO的接口实现类XxxDAOImpl,XxxDaoImpl

示例代码


注意,记得关闭Connection,Statement,ReusultSet等类似的资源,下面的代码都省去了关闭资源的步骤

  • IStudentDAO
public interface IStudentDAO {
  /**
  * 保存学生信息
  * @param stu 需要保存的学生对象
  */
  void save(Student stu);
  
  /**
  * 根据id删除对应的学生
  * @param id 需要删除学生的di
  */
  void delete(Long id);
  
  /**
  * 修改学生信息
  * @param stu 封装需要修改的学生信息
  */
  void update(Student stu);
  
  /**
  * 根据id获取对应学生的信息
  * @param Long id
  */
  Student get(Long id);
  
  /**
  * 查询所有的学生信息
  * @return
  */
  List<Student> list();
}
  • StudentDAOImpl(DML)
public void save(Student stu) {
  Connection conn = null;
  Statement stmt = null;
  try {
    // 加载驱动
    Class.forName("com.mysql.jdbc.Driver");
    // 获取连接对象
    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest", "root", "root");
    // 创建语句对象
    stmt = conn.createStatement();
    // 执行SQL语句
    // 使用StringBuilder进行拼接的速度比较快
    StringBuilder sb = new StringBuilder("INSERT INTO t_student VALUES (NULL,)");
    sb.append("'").append(stu.getName()).append(",");
    sb.append(stu.getAge());
    sb.append(")");
    System.out.prinln(sb);
    st.executeUpdate(sb.toString());
  } catch (Exception e) {
    e.printStackTrace();
  }
}

public void delete(Long id) {
  Connection conn = null;
  Statement stmt = null;
  try {
    // 加载驱动
    Class.forName("com.mysql.jdbc.Driver");
    // 获取连接对象
    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest", "root", "root");
    // 执行SQL语句
    String sql = "DELETE FROM t_student WHERE id = " + id;
    // 创建语句对象
    stmt = conn.createStatement();
    stmt.executeUpdate(sql);
  } catch (Exception e) {
    System.out.printStackTrace();
  }
}

public void update(Student stu) {
  Connection conn = null;
  Statement stmt = null;
  try {
    // 加载驱动
    Class.forName("com.mysql.jdbc.Driver");
    // 获取连接对象
    conn = DriverManageer.getConnection("jdbc:mysql://127.0.0.1:3306/mytest", "root", "root");
    // 创建语句对象
    stmt = conn.createStatement();
    // 执行SQL语句
    StringBuilder sb = new StringBuilder("UPDATE t_student SET name = ");
    sb.append("'").append(stu.getName()).append("' WHERE id = ").append(stu.getId());
    System.out.println(sb);
    stmt.executeUpdate(sb.toString);
  } catch (Exception e) {
    e.printStackTrace();
  }
}
  • StudentDAOImpl(DQL)
public Student get(Long id) {
  Connection conn = null;
  Statement stmt = null;
  ResultSet rs = null;
  try {
    // 加载注册驱动
    Class.forName("com.mysql.jdbc.Driver");
    // 获取连接对象
    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest", "root", "root");
    // 创建语句对象
    stmt = conn.createStatmenet();
    // 执行SQL语句
    String sql = "SELECT * FROM WHERE id = " + id;
    rs = stmt.executeQuery(sql);
    // 处理结果集
    if (rs.next()) {
      Student stu = new Student();
      stu.setId(id);
      stu.setName(rs.getString("name")
      stu.setAge(rs.getInt("age"));
      return stu;
    }
  } catch(Exception e) {
    e.printStackTrace();
  }
}

public List<Student> list() {
  Connection conn = null;
  Statament stmt = null;
  ResultSert rs = null;
  try {
    // 加载驱动
    Class.forName("com.mysql.jdcb.Driver");
    // 获取连接对象
    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest", "root", "root");
    // 创建语句对象
    stmt = conn.createStatement();
    // 执行sql语句
    String sql = "SELECT * FROM t_student";
    rs = st.executeQuery()
    while (rs.next()) {
      Student stu = new Student();
      stu.setId(rs.getLong("id"));
      stu.setName(rs.getString("name"));
      stu.setAge(rs.getInt("age"));
      // 将每个学生添加到List集合中
      list.add(stu);
    }
    return list;
  } catch(Exception e) {
    e.printStackTrace();
  }
}

预编译语句对象PreparedStatement


  • 概念

创建一个预编译语句对象,将带有占位符的SQL发送到数据库中进行编译

  • 注意事项

发送参数到数据库中执行sql,千万不要传递参数如果传递了参数,则会调用Statement的方法了

  • 示例代码①
boolean execute();
ResultSet executeQuery();
int executeUpdate();
  • 示例代码②
@Test
public void testStatement() throws Exception {
    Class.forName("com.mysql.jdbc.Driver");
    Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest", "root", "root");
    Statement stmt = conn.createStatement();
    stmt.executeUpdate("INSERT INTO t_student(name, age) VALUES('张三', 19)");
}

@Test
public void testPreparedStatement() throws Exception {
  Class.forName("com.mysql.jdbc.Driver");
  Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mytest", "root", "root");
  String sql = "INSERT INTO t_student(name, age) VALUES(?,?)";
  PreparedStatement pstmt = conn.prepareStatement(sql);
  // 为占位符设置参数
  ps.setString(1, "李四");
  ps.setInt(2, 200);
  ps.executeUpdate(); // 不要传递参数
  ps.close();
  conn.close();
}

实现DAO和CRUD的操作


public vod save(Student stu) {
  Connection conn = null;
  PreparedStatement pstmt = null;
  try {
    conn = JdbcUtil.getConnection();
    // 创建语句对象
    String sql = "INSERT INTO t_student VALUES(null, ?, ?)";
    ps = conn.prepareStatement(sql);
    // 为占位符设置
    ps.setString(1, stu.getName());
    ps.setInt(2, stu.getAge());
    ps.executeUpdate();
  } catch(Exception e) {
    e.printStackTrace();
  } finally {
    // 释放资源
    JdbcUtil.close(conn, pstmt, null);
  }
}

public Student get(Long id) {
  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  try {
    conn = JdbcUtil.getConnection();
    // 创建语句对象
    String sql = "SELECT * FROM t_student WHERE id=?";
    pstmt = conn.prepareStatement(sql);
    pstmt.setLong(1, id);
    // 执行SQL语句
    rs = pstmt.excecuteQuery();
    while (rs.next()) {
      Student stu = new Student();
      stu.setId(rs.getLong("id"));
      stu.setName(rs.getString("name"));
      stu.setAge(rs.getAge("age"));
      
      return stu;
    }
  } cathch(Exception e) {
    e.printStackTrace();
  } finally {
    JdbcUtil.close(conn, pstmt, rs);
  }
  return null;
}

Statement与preparedStatement的对比


  • PreparedStatement的优势
    • 语法简单,便于维护
    • 执行的效率更高(MySQL不支持)
    • 安全性更高(防止SQL注入)

数据库事务的概述


  • 事务(Transaction,简写为tx)

指一组逻辑操作单元,使数据从一种状态变换到另一种状态。

为确保数据库中数据的一致性,数据的操作应该是离散的成组的逻辑单元:

当每个逻辑操作单元全部完成时,数据的一致性可以保持。

而当这个单元中的一部分操作失败整个事物应全部视为错误,所有从起点以后的操作应全部回退到开始状态。

  • 事务的操作

给事务定义一个起点,然后对数据做修改操作,这时如果提交(commite),这些修改就永久地保存下来,如果回退(rollback),数据库管理系统将放弃所有的修改而回到开始事务时的状态。

  • 事务的ACID属性:(面试题)

1.原子性(Atomicity)

原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。(一损俱损)

2.一致性(Consistency)

事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏)

3.隔离性(Isolation)

事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作以及使用的数据对并发的其他事务是隔离的,各个事务之间不能互相干扰。

4.持久性(Durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响

  • DML的操作默认是自动提交的
try {
  // 1.将事务设置为手动提交(设置事务的起点)
  Connection对象.setAutoCommit(false);
  
  // 3.提交事务
  Connection对象.commit();
} catch (Exception e) {
  e.printStackTrace();
  // 2.执行事务回滚操作
  Connection对象.rollback();
}
  • 注意事项

1.在JDBC中,DML的事务是默认提交的,必须设置事务为手动提交

Connecton对象.setAutoCommit(false);

2.手动的提交事务.

connection对象.commit();

3.若出现异常则必须回滚事务:

connection对象.rollback();

MySQL中,InnoDB支持外键,MyISAM不支持外键,不支持事务.

大数据类型操作


  • 示例代码

将图片插入到数据库中

@Test
public void testInsert() throws Exception {
  Connection conn = JdbcUtil.getConnection();
  String sql = "INSERT INTO t_user(headImg) VALUES (?)";
  PreparedStatement pstmt = conn.prepareStatement(sql);
  InputStream in = new FileInputStream("asd.png");
  pstmt.setBlob(1, in);
  pstmt.executeUpdate();
  JdbcUtil.close(conn, pstmt, null);
  in.close();
}

@Test
public void testGet() throws Exception {
  Connection conn = JdbcUtil.getConnection();
  String sql = "SELET headImg FROM t_user WHERE id=?"
  PreparedStatement pstmt = conn.prepareStatement();
  ps.setLong(1, 2L);
  ResultSet rs = ps.executeQuery();
  if (rs.next()) {
    Blob blob = rs.getBlob("headImg");
    // 将二进制数据保存到磁盘中
    InputStream in = blob.getBinaryStream();
    // Java7的新特性,复制文件
    Files.copy(in, Paths.get("head.png"));
    in.close();
  }
  JdbcUtil.close(conn, pstmt, rs);
}

连接池的思想


  • 作用

合理利用连接资源

  • 注意

释放资源Connection对象.close()的时候是是把Connection对象放回连接池,而不是和数据库断开

Druid的使用


  • 使用的步骤
    • 导入jar包(druid-1.0.9.jar)
    • 操作的方式和DBCP大致一样
  • 示例代码
// 获取连接池对象
public static DataSource getDataSource() {
  BasicDataSource ds = new BasicDataSource();
  ds.setDriverClassName("com.mysql.jdbc.Driver");
  ds.setUserName("root");
  ds.setPassword("root");
  ds.setUrl("jdbc:mysql:///mytest");
  retru ds;
}

// 获取连接对象
public static Connection getConnection() throws Exception {
  //使用工厂类创建连接池
  DataSource ds = BasicDataSourceFactory.createDataSource(p);
  // 从连接池中获取对象
  return ds.getConnection();
}

代码重构


  • JdbcUtil
public class JdbcUtil {
  private static Properties p = new Properties();
  static {
    try {
       // 加载资源文件
       ClassLoader loader = Thread.currentThread().getContextClassLoader();
       InputStream ins = loader.getResourceAsStream("db.properties");
       p.load(in);
       // 加载注册驱动
       Class.forName(p.getProperty("driverClassName"));
     )
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
  
  // 获取连接对象
  public static Connection getConnection() throws Exception {
     return DriverManager.getConnection(p.getProperty("url"), p.getProperty("usernmae"), p.getProperty("password"));
  }
}

DML和DQL操作使用PreparedStatement代替Statement


  • 示例代码

DQL查询语句

String sql = "SELECT * FROM t_student";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();

DML修改语句

String sql = "INSERT INTO t_student(id, name) VALUES(null,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "ghyz");
pstmt.executeUpdate();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

  • JDBC概述 在Java中,数据库存取技术可分为如下几类:JDBC直接访问数据库、JDO技术、第三方O/R工具,如...
    usopp阅读 3,525评论 3 75
  • JDBC简介 SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。JDBC...
    奋斗的老王阅读 1,492评论 0 51
  • 0x01 前言   前序:http://www.jianshu.com/p/b5d88389444d   在上述操...
    菩提树下成魔阅读 9,035评论 1 1
  • 星期五是一年一度的运动会。我们班特别开心,终于来到了一年一度的运动会了。我参加的项目是跳远和八百米。 运动会开始了...
    垚儿_cec8阅读 365评论 2 4
  • 今天刚刚读完,思绪感慨万千! 「好处你们拿,黑锅我来背。」顺治皇上像是没有城府的小孩,稚气未脱。 因官员科举舞弊,...
    麦先生VBA阅读 1,984评论 0 0