對於須要批量插入數據庫操做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不須要判斷注參的緣由吧