JDBC批量插入數據效率分析

對於須要批量插入數據庫操做JDBC有多重方式,本利從三個角度對Statement和PreparedStatement兩種執行方式進行分析,總結較優的方案。java

當前實現由以下條件:sql

  執行數據庫:Mysql數據庫

執行數據數量:10萬條app

執行前提:執行差入數據庫錢均須要提供空表,防止數據量大形成的影響工具

執行方式:Statement和PreparedStatement兩種方式性能

 

執行步驟開始:url

一、建立表spa

1 CREATE TABLE T_PRODUCT (
2   ID bigint(12) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
3   NAME varchar(60) NOT NULL COMMENT '產品名稱',
4   WEIGHT varchar(60) NOT NULL COMMENT '產品重量',
5   MARK varchar(60) NOT NULL COMMENT '產品說明',
6   PRIMARY KEY (ID)
7 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='產品表';

二、編寫操做數據庫工具類3d

  1 package com.luwei.test.jdbc;
  2 
  3 import java.sql.Connection;
  4 import java.sql.DriverManager;
  5 import java.sql.SQLException;
  6 import java.sql.Statement;
  7 import java.util.ResourceBundle;
  8 
  9 /**
 10  * <Description> TODO<br>
 11  * 
 12  * @author lu.wei<br>
 13  * @email 1025742048@qq.com <br>
 14  * @date 2017年1月9日 <br>
 15  * @since V1.0<br>
 16  * @see com.luwei.test.jdbc <br>
 17  */
 18 public class JdbcTemplate {
 19     private static String DRIVER_CLASS_NAME = null;
 20     private static String URL = null;
 21     private static String USERNAME = null;
 22     private static String PASSWORD = null;
 23 
 24     static {
 25         ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
 26         DRIVER_CLASS_NAME = bundle.getString("jdbc.driverClassName");
 27         URL = bundle.getString("jdbc.url");
 28         USERNAME = bundle.getString("jdbc.username");
 29         PASSWORD = bundle.getString("jdbc.password");
 30     }
 31 
 32     /**
 33      * 
 34      * <Description> 獲取數據庫鏈接<br>
 35      * 
 36      * @author lu.wei<br>
 37      * @email 1025742048@qq.com <br>
 38      * @date 2017年1月9日 下午10:19:41 <br>
 39      * @return
 40      * @throws Exception
 41      * <br>
 42      */
 43     public static Connection getConnection() throws Exception {
 44         Class.forName(DRIVER_CLASS_NAME);
 45         Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
 46         return connection;
 47     }
 48 
 49     /**
 50      * 
 51      * <Description> 提交事務<br>
 52      * 
 53      * @author lu.wei<br>
 54      * @email 1025742048@qq.com <br>
 55      * @date 2017年1月9日 下午10:20:48 <br>
 56      * @param connection
 57      * <br>
 58      */
 59     public static void commit(Connection connection) {
 60         try {
 61             connection.commit();
 62         }
 63         catch (SQLException e) {
 64             e.printStackTrace();
 65         }
 66     }
 67 
 68     /**
 69      * 
 70      * <Description> 開啓事務<br>
 71      * 
 72      * @author lu.wei<br>
 73      * @email 1025742048@qq.com <br>
 74      * @date 2017年1月9日 下午10:23:56 <br>
 75      * @param connection
 76      * <br>
 77      */
 78     public static void beginTx(Connection connection) {
 79         try {
 80             connection.setAutoCommit(false);
 81         }
 82         catch (SQLException e) {
 83             e.printStackTrace();
 84         }
 85     }
 86 
 87     /**
 88      * 
 89      * <Description> 回滾<br>
 90      * 
 91      * @author lu.wei<br>
 92      * @email 1025742048@qq.com <br>
 93      * @date 2017年1月9日 下午10:24:33 <br>
 94      * @param connection
 95      * <br>
 96      */
 97     public static void rollback(Connection connection) {
 98         try {
 99             connection.rollback();
100         }
101         catch (SQLException e) {
102             e.printStackTrace();
103         }
104     }
105 
106     /**
107      * 
108      * <Description> TODO<br>
109      * 
110      * @author lu.wei<br>
111      * @email 1025742048@qq.com <br>
112      * @date 2017年1月9日 下午10:28:49 <br>
113      * @param statement
114      * @param connection
115      * <br>
116      */
117     public static void releaseDb(Statement statement, Connection connection) {
118         try {
119             statement.close();
120             connection.close();
121         }
122         catch (SQLException e) {
123             e.printStackTrace();
124         }
125     }
126 }

 

三、執行數據庫插入操做code

3.一、使用Statement直接插入,三次執行耗時:41979 42608 42490

 1 @Test
 2 public void testStatement() {
 3     Connection connection = null;
 4     Statement statement = null;
 5     try {
 6         connection = JdbcTemplate.getConnection();
 7         JdbcTemplate.beginTx(connection);
 8 
 9         statement = connection.createStatement();
10         long begin = System.currentTimeMillis();
11         for (int i = 0; i < 100000; i++) {
12             String sql = "insert into t_product values(null,'name_" + i + "','120kg','mark_" + i + "')";
13             statement.execute(sql);
14         }
15         long end = System.currentTimeMillis();
16         System.out.println(end - begin);
17         JdbcTemplate.commit(connection);
18     }
19     catch (Exception e) {
20         e.printStackTrace();
21         JdbcTemplate.rollback(connection);
22     }
23     finally {
24         JdbcTemplate.releaseDb(statement, connection);
25     }
26 }

3.二、使用PreparedStatement直接插入,三次執行耗時:22808 24675 22281

 1 @Test
 2 public void testPreparedStatement() {
 3     Connection connection = null;
 4     PreparedStatement statement = null;
 5     try {
 6         connection = JdbcTemplate.getConnection();
 7         JdbcTemplate.beginTx(connection);
 8         String sql = "insert into t_product values(null,?,?,?)";
 9 
10         statement = connection.prepareStatement(sql);
11         long begin = System.currentTimeMillis();
12         for (int i = 0; i < 100000; i++) {
13             statement.setString(1, "name_" + i);
14             statement.setString(2, "120kg");
15             statement.setString(3, "mark_" + i);
16             statement.executeUpdate();
17         }
18         long end = System.currentTimeMillis();
19         System.out.println(end - begin);
20         JdbcTemplate.commit(connection);
21     }
22     catch (Exception e) {
23         e.printStackTrace();
24         JdbcTemplate.rollback(connection);
25     }
26     finally {
27         JdbcTemplate.releaseDb(statement, connection);
28     }
29 }

3.三、使用BatchStatement直接插入,三次執行耗時:15342 15235 15485

 1 @Test
 2 public void testBatchStatement() {
 3     Connection connection = null;
 4     Statement statement = null;
 5     try {
 6         connection = JdbcTemplate.getConnection();
 7         JdbcTemplate.beginTx(connection);
 8 
 9         statement = connection.createStatement();
10         long begin = System.currentTimeMillis();
11         for (int i = 0; i < 100000; i++) {
12             String sql = "insert into t_product values(null,'name_" + i + "','120kg','mark_" + i + "')";
13             statement.addBatch(sql);
14 
15             if ((i + 1) % 100 == 0) {
16                 statement.executeBatch();
17                 statement.clearBatch();
18             }
19         }
20         statement.executeBatch();
21         statement.clearBatch();
22         long end = System.currentTimeMillis();
23         System.out.println(end - begin);
24         JdbcTemplate.commit(connection);
25     }
26     catch (Exception e) {
27         e.printStackTrace();
28         JdbcTemplate.rollback(connection);
29     }
30     finally {
31         JdbcTemplate.releaseDb(statement, connection);
32     }
33 }

3.四、使用BatchPreparedStatement直接插入,三次執行耗時:21913 22045 23291

 1 @Test
 2 public void testBatchPreparedStatement() {
 3     Connection connection = null;
 4     PreparedStatement statement = null;
 5     try {
 6         connection = JdbcTemplate.getConnection();
 7         JdbcTemplate.beginTx(connection);
 8         String sql = "insert into t_product values(null,?,?,?)";
 9 
10         statement = connection.prepareStatement(sql);
11         long begin = System.currentTimeMillis();
12         for (int i = 0; i < 100000; i++) {
13             statement.setString(1, "name_" + i);
14             statement.setString(2, "120kg");
15             statement.setString(3, "mark_" + i);
16             statement.addBatch();
17             if ((i + 1) % 100 == 0) {
18                 statement.executeBatch();
19                 statement.clearBatch();
20             }
21         }
22         statement.executeBatch();
23         statement.clearBatch();
24         long end = System.currentTimeMillis();
25         System.out.println(end - begin);
26         JdbcTemplate.commit(connection);
27     }
28     catch (Exception e) {
29         e.printStackTrace();
30         JdbcTemplate.rollback(connection);
31     }
32     finally {
33         JdbcTemplate.releaseDb(statement, connection);
34     }
35 }

3.五、使用採用多Value值Statement直接插入,三次執行耗時:2931 3007 3203 2964

 1 @Test
 2 public void testMutilValueStatement() {
 3     Connection connection = null;
 4     Statement statement = null;
 5     try {
 6         connection = JdbcTemplate.getConnection();
 7         JdbcTemplate.beginTx(connection);
 8 
 9         statement = connection.createStatement();
10 
11         StringBuffer sql = new StringBuffer("insert into t_product values");
12         long begin = System.currentTimeMillis();
13         for (int i = 0; i < 100000; i++) {
14             if (i != 0) {
15                 sql.append(",");
16             }
17             sql.append("(null,'name_" + i + "','120kg','mark_" + i + "')");
18         }
19         statement.execute(sql.toString());
20         long end = System.currentTimeMillis();
21         System.out.println(end - begin);
22         JdbcTemplate.commit(connection);
23     }
24     catch (Exception e) {
25         e.printStackTrace();
26         JdbcTemplate.rollback(connection);
27     }
28     finally {
29         JdbcTemplate.releaseDb(statement, connection);
30     }
31 }

3.六、使用採用多Value值PreparedStatement直接插入,三次執行耗時:3356 3218 3233

 1 @Test
 2 public void testMutilValuePreparedStatement() {
 3     Connection connection = null;
 4     PreparedStatement statement = null;
 5     try {
 6         connection = JdbcTemplate.getConnection();
 7         JdbcTemplate.beginTx(connection);
 8 
 9         StringBuffer sql = new StringBuffer("insert into t_product values");
10         long begin = System.currentTimeMillis();
11         for (int i = 0; i < 100000; i++) {
12             if (i != 0) {
13                 sql.append(",");
14             }
15             sql.append("(null,'name_" + i + "','120kg','mark_" + i + "')");
16         }
17         statement = connection.prepareStatement(sql.toString());
18         statement.executeUpdate();
19         long end = System.currentTimeMillis();
20         System.out.println(end - begin);
21         JdbcTemplate.commit(connection);
22     }
23     catch (Exception e) {
24         e.printStackTrace();
25         JdbcTemplate.rollback(connection);
26     }
27     finally {
28         JdbcTemplate.releaseDb(statement, connection);
29     }
30 }

 

經過以上時間結果得出以下數據表格:

 

 總結:經過如上的數據對比發現

  一、PreparedStatement執行數據庫插入比使用Statement執行數據庫插入明顯有性能優點,緣由歸功於PreparedStatement可以預先對SQL進行編譯,作到執行時進行SQL共享

  二、執行數據庫批量操做是使用Batch方式對數據庫採用批次操做可以明顯提高數據庫操做性能能

  三、無論是直接屢次插入數據庫仍是採用Batch方式執行數據庫的插入,均會發送屢次SQL腳本去執行,這樣明顯沒有發送一次SQL腳本執行來的效率高

  四、採用單SQL執行數據庫批量操做時Statement對比PreparedStatement有微弱的優點,多是Statement不須要判斷注參的緣由吧

相關文章
相關標籤/搜索