0%

JDBC

JDBC

★★★第二十一章 JDBC和数据库连接池

★★★JDBC原理示意图

  1. JDBC 为访问不同的数据库提供了统一的接口,为使用者屏蔽了细节问题。

  2. Java 程序员使用 JDBC可以连接任何提供了 JDBC 驱动程序的数据库系统,从而完成对数据库的各种操作。

    ![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/Java-notebook/img/Java/C21-1.jpg)

    JDBCJava 提供的一套用于数据库操作的接口 APl,**Java 程序员只需要面向这套接口编程即可不同的数据库厂商,需要针对这套接口,提供不同的实现**。

    ![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/Java-notebook/img/Java/C21-2.jpg)

  3. JDBC API 是一系列的接口,它统一和规范了应用程序与数据库的连接、执行 SQL 语句,并得到返回结果等各类操作,相关类和接口在 java.sqljavax.sql 包中。

★JDBC快速入门

  • JDBC 程序编写步骤(以使用 mysql 为例):

    前置工作:在项目下创建一个文件夹,例如 lib ,将 mysql.jar 文件拷贝到该目录下,通过添加库导入该 jar 包。-> MySQL中 java 的 JDBC 编程使用方法及驱动包的下载和使用 - CSDN博客

    1. 注册驱动 - 加载 Driver 类。
    2. 获取连接 - 得到 Connection
    3. 执行增删改查 - 发送 SQLmysql 执行。
    4. 释放资源 - 关闭相关连接。
  • 以下面的例子为例(java_db 是已经创建的一个数据库):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    package com.f.chapter21.jdbc;

    import com.mysql.jdbc.Driver;

    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;

    /**
    * @author fzy
    * @date 2023/8/4 19:21
    * JDBC 的快速入门
    */
    public class Jdbc01 {
    public static void main(String[] args) throws SQLException {
    //1.注册驱动
    Driver driver = new Driver(); //创建驱动对象

    //2.获取连接
    // (1) jdbc:mysql:// 是规定好的,用来表示协议。通过 jdbc 的方式连接 mysql
    // (2) localhost 表示主机,可以是 ip 地址
    // (3) 3306 表示 mysql 监听的端口
    // (4) java_db 表示连接到 MySQL DBMS 的 java_db 数据库
    //MySQL 连接的本质就是前面学过的 Socket 连接
    String url = "jdbc:mysql://localhost:3306/java_db?useSSL=false";
    //将用户名和密码放入到 Properties 对象中
    Properties properties = new Properties();
    // user 和 password 关键字是规定好的,不要乱写
    properties.setProperty("user", "root"); //用户
    properties.setProperty("password", "123456"); //密码
    Connection connect = driver.connect(url, properties);

    //3.执行sql
    String sql = "INSERT INTO test_table VALUES (100, 'tom')";
    //Statement 对象用于执行静态 SQL 语句并返回其生成的结果的对象。
    Statement statement = connect.createStatement(); //statement是帮我们执行sql语句的
    int rows = statement.executeUpdate(sql); //如果是dml语句,返回的就是影响的行数
    System.out.println(rows > 0 ? "sql语句执行成功" : "sql语句执行失败");

    //4.关闭连接,释放资源
    statement.close();
    connect.close();
    }
    }
    • 总结就是:
      • 用驱动 Driver 进行数据库的连接。
      • 用连接 Connection 创建 Statement
      • Statement 对象执行静态 SQL 语句并返回其生成的结果的对象。

★数据库连接的五种方式

  1. 直接使用 Driver 进行数据库的连接:

    1
    2
    3
    4
    5
    6
    7
    8
    Driver driver = new com.mysql.jdbc.Driver();

    String url = "jdbc:mysql://localhost:3306/java_db?useSSL=false";
    Properties properties = new Properties();
    properties.setProperty("user", "root"); //用户
    properties.setProperty("password", "123456"); //密码

    Connection connect = driver.connect(url, properties);
    • 缺点是 com.mysql.jdbc.Driver 是第三方的,而且是静态加载,灵活性不足,依赖强。
  2. 通过反射机制连接数据库:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Class clazz = Class.forName("com.mysql.jdbc.Driver");   //参数可以通过配置文件导入
    Driver driver = (Driver)clazz.newInstance();

    String url = "jdbc:mysql://localhost:3306/java_db?useSSL=false";
    Properties properties = new Properties();
    properties.setProperty("user", "root"); //用户
    properties.setProperty("password", "123456"); //密码

    Connection connect = driver.connect(url, properties);
    • 是动态加载,更加灵活,降低了依赖性。
  3. 使用 DriverManager 替代 Driver,进行统一管理:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Class clazz = Class.forName("com.mysql.jdbc.Driver");
    Driver driver = (Driver) clazz.newInstance();

    String url = "jdbc:mysql://localhost:3306/java_db?useSSL=false";
    Properties properties = new Properties();
    properties.setProperty("user", "root"); //用户
    properties.setProperty("password", "123456"); //密码

    DriverManager.registerDriver(driver); //注册Driver驱动

    Connection connection = DriverManager.getConnection(url, properties);
    • DriverManager 是用于管理一组 JDBC 驱动程序的基本服务。
  4. 使用 Class.forName 自动完成注册驱动,简化代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //使用反射加载 Driver 类
    /**
    * 在加载 Driver 类时,静态代码块会执行一次:
    * static {
    * try {
    * DriverManager.registerDriver(new Driver());
    * } catch (SQLException var1) {
    * throw new RuntimeException("Can't register driver!");
    * }
    * }
    * 该静态代码块的执行完成了注册 Driver 的工作
    * */
    Class.forName("com.mysql.jdbc.Driver");

    String url = "jdbc:mysql://localhost:3306/java_db?useSSL=false";
    Properties properties = new Properties();
    properties.setProperty("user", "root"); //用户
    properties.setProperty("password", "123456"); //密码

    Connection connection = DriverManager.getConnection(url, properties);
    • 注意:从 mysql 驱动 5.1.6 开始就可以无需显式使用Class.forName("com.mysql.jdbc.Driver")

      jdk1.5 以后使用了 jdbc4,不再需要显式调用 class.forName() 注册驱动而是自动调用驱动 jar 包下的 META-INF\services\java.sql.Driver 文本中的类名称去注册。

      • 建议还是写上 Class.forName("com.mysql.jdbc.Driver"),更加明确
  5. 基于方式 4 的优化,通过使用配置文件,使得连接数据库更加灵活:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //使用配置文件,连接数据库更加灵活
    Properties properties = new Properties();
    properties.load(new FileInputStream("file\\jdbc.properties"));
    String user = properties.getProperty("user");
    String password = properties.getProperty("password");
    String url = properties.getProperty("url");
    String driver = properties.getProperty("driver");

    Class.forName(driver); //建议写上
    Connection connection = DriverManager.getConnection(url, user, password);
    • 以这种方式获取连接是使用的最多的,推荐使用

★★★ResultSet

  • public interface ResultSet extends Wrapper, AutoCloseable

    表示数据库结果集的数据表,通常通过执行查询数据库的语句生成

    • ResultSet 对象保持一个光标,指向其当前的数据行。 最初,光标位于第一行之前。 next方法将光标移动到下一行,并且由于在 ResultSet 对象中没有更多行时返回 false ,因此可以在 while 循环中使用循环来遍历结果集。

      有点类似于迭代器 iterator

    • ResultSet 对象通过 getXxx(i) 得到光标指向的当前行的第 i 列的数据(从 1 开始)

      也可以通过 getXxx("列名") 来得到光标指向的当前行的对应列的数据。-> 更推荐用这种

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    package com.f.chapter21.jdbc.resultset_;

    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    import java.util.Properties;

    /**
    * @author fzy
    * @date 2023/8/5 20:45
    * 演示SELECT语句返回ResultSet,并取出结果
    */
    public class ResultSet_ {
    public static void main(String[] args) throws Exception {
    //1.连接数据库,得到Statement对象
    Properties properties = new Properties();
    properties.load(new FileInputStream("file\\jdbc.properties"));
    String driver = properties.getProperty("driver");
    String url = properties.getProperty("url");
    String user = properties.getProperty("user");
    String password = properties.getProperty("password");
    // (1)注册驱动
    Class.forName(driver);
    // (2)得到连接
    Connection connection = DriverManager.getConnection(url, user, password);
    // (3)得到Statement对象
    Statement statement = connection.createStatement();

    //2.执行SELECT语句,返回ResultSet
    String selectSQL = "SELECT * " +
    "FROM `news`";
    ResultSet resultSet = statement.executeQuery(selectSQL);

    //3.通过while循环取出 ResultSet 中的数据
    while (resultSet.next()) { //让光标向后移动,如果没有更多行则返回 `false`
    int id = resultSet.getInt(1); //获取当前记录的第一列数据
    String content = resultSet.getString(2); //获取当前记录的第二列数据
    System.out.println(id + " - " + content);
    }

    //4.释放资源
    resultSet.close();
    statement.close();
    connection.close();
    }
    }

★★★Statement

  • public interface Statement extends Wrapper, AutoCloseable

    用于执行静态SQL语句并返回其生成的结果的对象。

SQL注入
  1. 在连接建立后,需要对数据库进行访问,执行命名是 SQL 语句,可以通过

    • Statement [存在SQL注入] -> 在实际开发中不会使用
    • PreparedStatement [预处理]
    • CallableStatement [调用存储过程]

    执行。

  2. Statement 对象执行 SQL 语句,存在 SQL 注入风险。

  3. SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,恶意攻击数据库

  4. 要防范 SQL 注入,只要PreparedStatement (从 Statement 扩展而来)取代 Statement 就可以了。

★PreparedStatement
  • public interface PreparedStatement extends Statement

    表示预编译的SQL语句的对象。

    SQL语句已预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句。

  1. PreparedStatement 执行的 SQL 语句中的参数用问号 ? 来表示,通过调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数

    1
    String sql = "SELECT COUNT(*) FROM admin WHERE user = ? AND password = ?";

    setXxx() 方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从 1 开始)第二个是设置的 SQL 语句中的参数的值

  2. 调用 executeQuery(String sql),返回的是 ResultSet 对象

  3. 调用 executeUpdate(String sql),执行更新,包括增、删、修改,返回的是影响的行数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.f.chapter21.jdbc.preparedstatement_;

import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;

/**
* @author fzy
* @date 2023/8/5 21:49
*/
public class PreparedStatement_ {
public static void main(String[] args) throws Exception {
//1.连接数据库,得到 PreparedStatement 对象
Properties properties = new Properties();
properties.load(new FileInputStream("file\\jdbc.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
// (1)注册驱动
Class.forName(driver);
// (2)得到连接
Connection connection = DriverManager.getConnection(url, user, password);
// (3)传入sql语句,得到PreparedStatement对象
// sql语句的 ? 就相当于占位符
String selectSQL = "SELECT * FROM news WHERE id = ?";
//该PreparedStatement对象是实现了PreparedStatement接口的类的对象,PreparedStatement是一个接口
PreparedStatement preparedStatement = connection.prepareStatement(selectSQL);

//2.通过 PreparedStatement 对象执行 sql 语句,得到执行的结果
// (1)给 ? 赋值
preparedStatement.setInt(1, 2);
// (2)执行sql语句
// 这里执行查询的时候,不需要再传入sql语句了,
// 因为在创建PreparedStatement对象时,已经将sql语句和该对象关联起来了。
// 而且就算传入了sql语句,就相当于
// ResultSet resultSet = preparedStatement.executeQuery("SELECT * FROM news WHERE id = ?");
// 语法是错误的,执行也不会成功
ResultSet resultSet = preparedStatement.executeQuery();

//3.通过while循环取出 ResultSet 中的数据
while (resultSet.next()) { //让光标向后移动,如果没有更多行则返回 `false`
int id = resultSet.getInt(1); //获取当前记录的第一列数据
String content = resultSet.getString(2); //获取当前记录的第二列数据
System.out.println(id + " - " + content);
}

//4.释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
}
  • 预处理的好处:
    1. 不再使用 + 拼接 sql 语句,减少语法错误。
    2. 有效的解决了 sql 注入问题。
    3. 大大减少了编译次数,效率较高。

★★★JDBC API小结

![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/Java-notebook/img/Java/C21-3.jpg)

![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/Java-notebook/img/Java/C21-4.jpg)

JDBC工具类

  • JDBC 操作中,“获取连接” 和 “释放资源” 是经常使用到的,可以将其封装为 JDBC 连接的工具类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    package com.f.chapter21.jdbc.utils;

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.sql.*;
    import java.util.Properties;

    /**
    * @author fzy
    * @date 2023/8/6 13:32
    * JDBC的工具类,完成mysql的连接和关闭资源
    */
    public class JDBCUtils {
    //定义相关属性
    private static String driver; //驱动名
    private static String url; //连接数据库的url
    private static String user; //用户名
    private static String password; //密码

    //在static代码块去初始化相关属性
    static {
    Properties properties = new Properties();
    try {
    properties.load(new FileInputStream("file\\jdbc.properties"));
    driver = properties.getProperty("driver");
    url = properties.getProperty("url");
    user = properties.getProperty("user");
    password = properties.getProperty("password");
    } catch (IOException e) {
    //在实际开发中,我们可以这样处理:
    // 1.将编译异常用运行时异常抛出
    // 2.这时调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便
    throw new RuntimeException(e);
    }
    }

    //连接数据库,返回Connection对象
    public static Connection getConnection() {
    try {
    Class.forName(driver);
    return DriverManager.getConnection(url, user, password);
    } catch (ClassNotFoundException e) {
    throw new RuntimeException(e);
    } catch (SQLException e) {
    throw new RuntimeException(e);
    }
    }

    /**
    * 关闭相关资源:
    * 1.结果集 ResultSet
    * 2.Statement 或者 PreparedStatement
    * 3.Connection
    * 4.如果需要关闭资源,就传入对象,否则传入null
    */
    public static void close(ResultSet set, Statement statement, Connection connection) {
    try {
    if (set != null) {
    set.close();
    }
    if (statement != null) {
    statement.close();
    }
    if (connection != null) {
    connection.close();
    }
    } catch (SQLException e) {
    throw new RuntimeException(e);
    }
    }
    }
  • JDBC 工具类的使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    package com.f.chapter21.jdbc.utils;

    import org.junit.jupiter.api.Test;

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;

    /**
    * @author fzy
    * @date 2023/8/6 13:58
    * 演示如何使用JDBCUtils工具类,完成dml和select语句
    */
    public class JDBCUtils_Use {
    @Test
    public void testDML() {
    //1.得到连接
    Connection connection = JDBCUtils.getConnection();
    System.out.println(connection.getClass()); //class com.mysql.jdbc.JDBC4Connection
    //2.组织一个dml sql语句
    String insertSQL = "INSERT INTO test_table VALUES (?, ?)";
    //3.创建PreparedStatement对象
    PreparedStatement preparedStatement = null;
    try {
    preparedStatement = connection.prepareStatement(insertSQL);
    //给占位符 ? 赋值
    preparedStatement.setInt(1, 1);
    preparedStatement.setString(2, "北京新闻");
    //执行dml sql语句
    preparedStatement.executeUpdate();
    } catch (SQLException e) {
    throw new RuntimeException(e);
    } finally {
    //4.关闭资源
    JDBCUtils.close(null, preparedStatement, connection);
    }
    }

    @Test
    public void testSelect() {
    //1.得到连接
    Connection connection = JDBCUtils.getConnection();
    //2.组织一个select sql语句
    String selectSQL = "SELECT * FROM test_table WHERE id = ?";
    //3.创建PreparedStatement对象
    PreparedStatement preparedStatement = null;
    //4.创建ResultSet对象
    ResultSet resultSet = null;
    try {
    preparedStatement = connection.prepareStatement(selectSQL);
    //给占位符 ? 赋值
    preparedStatement.setInt(1, 1);
    //执行select sql语句,得到 ResultSet 结果集
    resultSet = preparedStatement.executeQuery();
    while (resultSet.next()) {
    System.out.println(resultSet.getInt("id") + " - " + resultSet.getString("name"));
    }
    } catch (SQLException e) {
    throw new RuntimeException(e);
    } finally {
    //5.关闭资源
    JDBCUtils.close(resultSet, preparedStatement, connection);
    }
    }
    }

事务

  1. JDBC 程序中当一个 Connection 对象创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
  2. JDBC 程序中为了让多个 SQL 语句作为一个整体执行,需要使用事务。
  3. 调用 ConnectionsetAutoCommit(false) 可以取消自动提交事务。
  4. 在所有的 SQL 语句都成功执行后,调用 Connectioncommit() 方法提交事务
  5. 在其中某个操作失败或出现异常时,调用 Connectionrollback() 方法回滚事务
    • rollback() 方法可以放在异常的 catch 块中。
  • 以转账业务为例进行代码的编写:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    package com.f.chapter21.jdbc.transaction;

    import com.f.chapter21.jdbc.utils.JDBCUtils;
    import org.junit.jupiter.api.Test;

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;

    /**
    * @author fzy
    * @date 2023/8/6 14:50
    * 演示在JDBC中事务的使用
    */
    public class Transaction_ {
    @Test
    public void testTransaction_() {
    //1.得到连接
    //Connection在默认情况下是自动提交事务的
    Connection connection = JDBCUtils.getConnection();
    //2.组织sql语句
    String sql1 = "UPDATE account SET balance = balance - 100 WHERE id = 1";
    String sql2 = "UPDATE account SET balance = balance + 100 WHERE id = 2";
    //3.创建PreparedStatement对象
    PreparedStatement preparedStatement = null;
    try {
    //取消Connection自动提交事务,也是事务开始的地方
    connection.setAutoCommit(false);

    preparedStatement = connection.prepareStatement(sql1);
    preparedStatement.executeUpdate(); //执行第一条sql
    //...
    //可能发生异常,出现程序无法继续运行下去的情况,例如下面的语句
    //int i = 1 / 0;
    //...
    preparedStatement = connection.prepareStatement(sql2);
    preparedStatement.executeUpdate(); //执行第二条sql

    //如果程序正常运行,则可以在这里进行事务的提交
    connection.commit();
    } catch (Exception e) {
    try {
    //可以在这里进行回滚,撤销已经执行的sql
    //默认回滚到事务开始的地方
    System.out.println("发生了异常,撤销执行的sql,进行回滚");
    connection.rollback();
    } catch (SQLException ex) {
    throw new RuntimeException(ex);
    }
    throw new RuntimeException(e);
    } finally {
    //4.关闭资源
    JDBCUtils.close(null, preparedStatement, connection);
    }
    }
    }

批处理

  1. 当需要成批插入或者更新记录时。可以采用 Java 的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。

  2. JDBC 的批量处理语句包括下面方法:

    • addBatch():添加需要批量处理的 SQL 语句或参数。
    • executeBatch():执行批量处理语句。
    • clearBatch():清空批处理包的语句。
  3. JDBC 连接 MySQL 时,如果要使用批处理功能,请在 url 中添加参数:

    **?rewriteBatchedStatements=true**。

  4. 批处理往往和 PreparedStatement 一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.f.chapter21.jdbc.batch;

import com.f.chapter21.jdbc.utils.JDBCUtils;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;

/**
* @author fzy
* @date 2023/8/7 16:06
* 演示Java进行批处理和不进行批处理的区别
*/
public class Batch_ {
@Test
public void noBatch() throws Exception {
Connection connection = JDBCUtils.getConnection();
PreparedStatement preparedStatement = null;
String sql = "INSERT INTO admin VALUES (null, ?, ?)";
preparedStatement = connection.prepareStatement(sql);
//执行五千次insert操作
long start = System.currentTimeMillis(); //执行开始时间
for (int i = 0; i < 5000; i++) {
preparedStatement.setString(1, "tom" + i);
preparedStatement.setString(2, "123456" + i);
preparedStatement.executeUpdate();
}
long end = System.currentTimeMillis(); //执行结束时间
System.out.println("执行总耗时 = " + (end - start)); //执行总耗时 = 7420
JDBCUtils.close(null, preparedStatement, connection);
}

@Test
public void batch() throws Exception {
Connection connection = JDBCUtils.getConnection();
PreparedStatement preparedStatement = null;
String sql = "INSERT INTO admin VALUES (null, ?, ?)";
preparedStatement = connection.prepareStatement(sql);
//执行五千次insert操作
long start = System.currentTimeMillis(); //执行开始时间
for (int i = 0; i < 5000; i++) {
preparedStatement.setString(1, "tom" + i);
preparedStatement.setString(2, "123456" + i);
/**
* 将sql语句加入到批处理包batchedArgs中:
* public void addBatch() throws SQLException {
* synchronized(this.checkClosed().getConnectionMutex()) {
* if (this.batchedArgs == null) {
* //创建ArrayList, 里面将要存放的是PreparedStatement$BatchParams对象,即预处理的sql语句
* this.batchedArgs = new ArrayList();
* }
*
* //对PreparedStatement传入的参数进行校验并对相应的sql进行预处理
* for(int i = 0; i < this.parameterValues.length; ++i) {
* this.checkAllParametersSet(this.parameterValues[i], this.parameterStreams[i], i);
* }
*
* this.batchedArgs.add(new BatchParams(this.parameterValues, this.parameterStreams, this.isStream, this.streamLengths, this.isNull));
* }
* }
* */
preparedStatement.addBatch();
//当batch中有1000条记录时,再批量执行
if ((i + 1) % 1000 == 0) {
preparedStatement.executeBatch();
//批量执行结束后,清空batch
preparedStatement.clearBatch();
}
}
long end = System.currentTimeMillis(); //执行结束时间
System.out.println("执行总耗时 = " + (end - start)); //执行总耗时 = 100
JDBCUtils.close(null, preparedStatement, connection);
}
}
---------------The End---------------