JDBC系列——4 Statement

本文是 JDBC 系列文章的第四篇,本文将对 Statement 接口进行介绍,由于本人菜鸟一枚,文中若有错误之处,还请各位朋友批评指正,感谢大家花费时间阅读。


Statement 是用于执行静态 SQL 语句,并返回结果。它还有两个子接口,一个用于执行动态 SQL 语句的 PreparedStatement,一个用于执行存储过程或函数的 CallableStatement。本文主要介绍 Statement 接口的使用。它为用户提供了以下主要方法:

// 执行一条 Select 的 SQL 语句,并返回对应的结果集
ResultSet executeQuery(String sql) throws SQLException;
// 执行一条无返回值的 DDL 语句,或执行 Data Manipulation Language(DML语句,如 INSERT、UPDATE、DELETE)语句
int executeUpdate(String sql) throws SQLException;
// 释放资源
void close() throws SQLException;
// 执行一条 SQL 语句,可能返回多个结果。需要配合 getResultSet 或 getUpdateCount 和 getMoreResults 方法一起使用。如果第一个结果是一个 ResultSet 对象,则返回true, 若是一个更新数量或无结果,则返回false
boolean execute(String sql) throws SQLException;
// 返回 execute 返回的结果集
ResultSet getResultSet() throws SQLException;
// 返回 execute 返回的更新数量
int getUpdateCount() throws SQLException;
// 返回 execute 方法是否还有更多的结果
boolean getMoreResults() throws SQLException;
// 将 SQL 语句加入列表中,通过 executeBatch 方法批量执行。
void addBatch( String sql ) throws SQLException;
// 清空 SQL 语句列表
void clearBatch() throws SQLException;
// 批量执行 SQL 列表中的语句,如果全部执行成功,则返回一个更新数量的数组。如果其中的某条语句发生错误,则根据数据库和驱动的支持来判断是继续执行后面的语句还是停止执行。
int[] executeBatch() throws SQLException;
// 获取执行的 SQL 语句返回的自增主键,如果为生成任何值,则返回一个空的 ResultSet 对象。
ResultSet getGeneratedKeys() throws SQLException;
// 执行 SQL 语句,并根据 autoGeneratedKeys 参数的设置返回结果。若为 Statement.RETURN_GENERATED_KEYS,则返回受影响的行数,然后调用 getGeneratedKeys 得到key值,若为 Statement.NO_GENERATED_KEYS,则返回0。
int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException;
// 终止一次 SQL 语句的执行,前提是数据库和驱动都支持。用于多线程环境下。
void cancel() throws SQLException;

知道 Statement 提供的方法后,我们就用几个实例来简单测试一下。 1. executeQuery 方法 ```java public static void testExecuteQuery() { Connection connection = null; Statement statement = null; ResultSet resultSet = null;

try {
    String sql = "SELECT id, name FROM users";
    Class.forName("com.mysql.jdbc.Driver");
    connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "123456");
    statement = connection.createStatement();
    resultSet = statement.executeQuery(sql);

    while (resultSet.next()) {
        int id = resultSet.getInt("id");
        String name = resultSet.getString("name");

        System.out.println("id = " + id + " name = " + name);
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (resultSet != null) {
        try {
            resultSet.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    if (statement != null) {
        try {
            statement.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    if (connection != null) {
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
} } ```
  1. executeUpdate 方法 ```java public static void testExecuteUpdate() { Connection connection = null; Statement statement = null;

try { String sql = “INSERT INTO users(id, name) VALUES(20, ‘Kobe’); “; Class.forName(“com.mysql.jdbc.Driver”); connection = DriverManager.getConnection(“jdbc:mysql://localhost:3306/jdbc”, “root”, “123456”); statement = connection.createStatement(); int count = statement.executeUpdate(sql);

  System.out.println("count = " + count);   } catch (Exception e) {
  e.printStackTrace();   } finally {
  if (statement != null) {
      try {
          statement.close();
      } catch (SQLException e) {
          e.printStackTrace();
      }
  }

  if (connection != null) {
      try {
          connection.close();
      } catch (SQLException e) {
          e.printStackTrace();
      }
  }   } } ```
  1. executeUpdate 方法 和 getGeneratedKeys 方法 ```java public static void testExecuteUpdateGenerateKeys(){ Connection connection = null; Statement statement = null;

    try { String sql = “INSERT INTO users(name) VALUES(‘Tim’); “; Class.forName(“com.mysql.jdbc.Driver”); connection = DriverManager.getConnection(“jdbc:mysql://localhost:3306/jdbc”, “root”, “123456”); statement = connection.createStatement(); int count = statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); ResultSet rs = statement.getGeneratedKeys(); rs.next(); int key = rs.getInt(1); System.out.println(“key = “ + key); } catch (Exception e) { e.printStackTrace(); } finally { if (statement != null) { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } }

     if (connection != null) {
         try {
             connection.close();
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }  } } ```
    
  2. addBatch 方法 和 executeBatch 方法,本例重点比较执行多条大批量插入时,使用 executeBatch 返回和使用 for 循环的方式执行多次 executeUpdate 方法在性能上的差异 ```java public static void testExecuteBatch() { Connection connection = null; Statement statement = null; try { Class.forName(“com.mysql.jdbc.Driver”); connection = DriverManager.getConnection(“jdbc:mysql://localhost:3306/jdbc”, “root”, “123456”); statement = connection.createStatement();

     for (int i = 0; i < 100000; i++) {
         String sql = "INSERT INTO users(name) VALUES('Tim " + i + "'); ";
         statement.addBatch(sql);
     }
    
     statement.executeBatch();  } catch (Exception e) {
     e.printStackTrace();  } finally {
     if (statement != null) {
         try {
             statement.close();
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }
    
     if (connection != null) {
         try {
             connection.close();
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }  } }
    

public static void main(String[] args) { long start_batch = System.currentTimeMillis(); testExecuteBatch(); long end_batch = System.currentTimeMillis(); System.out.println(“use executeBatch : “ + (end_batch - start_batch));

long start_for = System.currentTimeMillis();
testExecuteUpdateUseFor();
long end_for = System.currentTimeMillis();
System.out.println("use for : " + (end_for - start_for)); }

/* use executeBatch : 10185 use for : 7866 */ ```

经过测试,发现使用 executeBatch 进行批量执行反而效率略差。由于本人经验不足,所以不确定结果是否正确,需要查询一下资料,明日来添加结果分析。

此坑难填啦。。。还请知道原因的大牛赐教!

通过上面的介绍和实例,Statement 接口就介绍忘了,下篇将对子接口 PreparedStatement 进行介绍。