JDBC批量插入主要用于數據導入和日志記錄因為日志一般都是先寫(xiě)在文件下的等。
我用Mysql 5.1.5的JDBC driver 分別對三種比較常用的方法做了測試
- 方法一,使用PreparedStatement加批量的方法
-
- try {
- Class.forName("com.mysql.jdbc.Driver");
- conn = DriverManager.getConnection(o_url, userName, password);
- conn.setAutoCommit(false);
- String sql = "INSERT adlogs(ip,website,yyyymmdd,hour,object_id) VALUES(?,?,?,?,?)";
- PreparedStatement prest = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
- for(int x = 0; x < size; x++){
- prest.setString(1, "192.168.1.1");
- prest.setString(2, "localhost");
- prest.setString(3, "20081009");
- prest.setInt(4, 8);
- prest.setString(5, "11111111");
- prest.addBatch();
- }
- prest.executeBatch();
- conn.commit();
- conn.close();
- } catch (SQLException ex) {
- Logger.getLogger(MyLogger.class.getName()).log(Level.SEVERE, null, ex);
- } catch (ClassNotFoundException ex) {
- Logger.getLogger(MyLogger.class.getName()).log(Level.SEVERE, null, ex);
- }
try {Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection(o_url, userName, password);conn.setAutoCommit(false);String sql = "INSERT adlogs(ip,website,yyyymmdd,hour,object_id) VALUES(?,?,?,?,?)";PreparedStatement prest = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);for(int x = 0; x < size; x++){prest.setString(1, "192.168.1.1");prest.setString(2, "localhost");prest.setString(3, "20081009");prest.setInt(4, 8);prest.setString(5, "11111111");prest.addBatch();}prest.executeBatch();conn.commit();conn.close();} catch (SQLException ex) {Logger.getLogger(MyLogger.class.getName()).log(Level.SEVERE, null, ex);} catch (ClassNotFoundException ex) {Logger.getLogger(MyLogger.class.getName()).log(Level.SEVERE, null, ex);}說(shuō)明下在建Statement的時(shí)候,后面兩個(gè)參數的意義:
第一個(gè)參數指定 ResultSet 的類(lèi)型。其選項有:
TYPE_FORWARD_ONLY:缺省類(lèi)型。只允許向前訪(fǎng)問(wèn)一次,并且不會(huì )受到其他用戶(hù)對該數據庫所作更改的影響。
TYPE_SCROLL_INSENSITIVE:允許在列表中向前或向后移動(dòng),甚至可以進(jìn)行特定定位,例如移至列表中的第四個(gè)記錄或者從當前位置向后移動(dòng)兩個(gè)記錄。不會(huì )受到其他用戶(hù)對該數據庫所作更改的影響。
TYPE_SCROLL_SENSITIVE:象 TYPE_SCROLL_INSENSITIVE 一樣,允許在記錄中定位。這種類(lèi)型受到其他用戶(hù)所作更改的影響。如果用戶(hù)在執行完查詢(xún)之后刪除一個(gè)記錄,那個(gè)記錄將從 ResultSet 中消失。類(lèi)似的,對數據值的更改也將反映在 ResultSet 中。
第二個(gè)參數設置 ResultSet 的并發(fā)性,該參數確定是否可以更新 ResultSet。其選項有:
CONCUR_READ_ONLY:這是缺省值,指定不可以更新
ResultSet CONCUR_UPDATABLE:指定可以更新 ResultSet
-
- conn.setAutoCommit(false);
- Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
- for(int x = 0; x < size; x++){
- stmt.addBatch("INSERT INTO adlogs(ip,website,yyyymmdd,hour,object_id) VALUES('192.168.1.3', 'localhost','20081009',8,'23123')");
- }
- stmt.executeBatch();
- conn.commit();
conn.setAutoCommit(false);Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);for(int x = 0; x < size; x++){stmt.addBatch("INSERT INTO adlogs(ip,website,yyyymmdd,hour,object_id) VALUES('192.168.1.3', 'localhost','20081009',8,'23123')");}stmt.executeBatch();conn.commit(); - conn.setAutoCommit(false);
- Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
- ResultSet.CONCUR_READ_ONLY);
- for(int x = 0; x < size; x++){
- stmt.execute("INSERT INTO adlogs(ip,website,yyyymmdd,hour,object_id) VALUES('192.168.1.3', 'localhost','20081009',8,'23123')");
- }
- conn.commit();
conn.setAutoCommit(false);Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);for(int x = 0; x < size; x++){stmt.execute("INSERT INTO adlogs(ip,website,yyyymmdd,hour,object_id) VALUES('192.168.1.3', 'localhost','20081009',8,'23123')");}conn.commit();使用上述方法分別插入10萬(wàn)條數據的平均測試時(shí)間為:
方法一:
17.844s
方法二:
18.421s
方法三:
16.359s
可以看出JDBC的batch語(yǔ)句插入不但沒(méi)有性能提升,反而比沒(méi)有用batch的時(shí)候要慢,當然這可能跟JDBC具體驅動(dòng)的實(shí)現方法有關(guān)。 附件中是我測試代碼,可以用來(lái)在自己電腦上跑一下。
在執行批量插入的時(shí)候最主要的是將自動(dòng)提交取消,這樣不管是否用JDBC的batch語(yǔ)法應該都沒(méi)有關(guān)系。