使用JDBC對數據庫實現批處理操作


  本篇講述如何使用JDBC對數據庫實現批處理操作。很多時候單條SQL命令不能滿足我們的需求,我們需要對數據庫一次實現很多操作,需要發送一批SQL命令給數據庫執行。

  而JDBC也提供了相應的方法給我們實現批處理操作。分別使用Statement對象或者PreparedStatement對象。這兩種方式分別有着不同的運用場景:

  ⑴ 使用Statement對象

     優點:能發送多條不同操作類型的SQL命令,也就是說在這發送的一批SQL語句中可以有各種增刪改查命令。

     缺點:雖然能發送多條不同操作類型的SQL命令,但沒有預編譯,因此在數據庫這一批中的每條SQL都需要編譯和執行兩個步驟。

  ⑵ 使用PreparedStatement對象

     優點:發送的是預編譯后的SQL語句,數據庫對這一批SQL命令只需要執行這一個步驟即可。

     缺點:只能發送多條相同操作類型,但占位符參數可以不同的SQL命令。也就是說這一批SQL要么是更新,要么是添加等等。稍后會介紹。

 

操作:

  ① 無論是Statement對象還是PreparedStatement對象,內部都含有一個List集合來保存一批多條SQL語句。兩個對象都使用addBatch方法來添加每一條SQL語句(Statement使用有參的addBatch方法,PreparedStatement使用無參的addBatch方法,后面會介紹到)。

  ② 當Statement對象或PreparedStatement對象都添加完一批SQL之后,都使用executeBatch()方法來使數據庫執行批處理,完成后返回一個整型數組int[],該整型數組中的元素的順序對應於提交給Statement對象或PreparedStatement對象的SQL語句順序,如果返回的是大於或等於0的數則表示成功處理並給出執行所影響的行數。當然改數組還會是別的內容,具體請看相關API文檔:

  

  ③ 在每次執行完executeBatch()方法后,請一定要再調用clearBatch()方法,將清空Statement對象或PreparedStatement對象中List集合保存的SQL命令列表。

  ④ 在使用批處理操作時,且不可一次執行過多SQL命令,例如幾千萬次,尤其是在使用PreparedStatement對象的方式情況下,極容易造成程序內存溢出。對於要執行過多次的操作,請將執行次數再分成各小批分別執行。

  下面分別以使用Statement對象和使用PreparedStatement對象的兩個例子來說明兩種批處理方式的不同之處。

例1:使用Statement對象進行批處理

  在這個案例中,我使用Statement對象進行批處理操作同時包含了插入和修改兩種操作,如果該批處理成功執行就說明了使用Statement對象能進行不同類型的數據庫操作。

創建數據庫和表:

create database jdbcdemo; use jdbcdemo; create table batchtest ( id int primary key, name varchar(40) )

創建工程,在工程中導入數據庫連接驅動的jar包。在【src】目錄下新建一個database.properties文件,內容如下:

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/jdbcdemo
    username=root
    password=root

  構建JDBC的工具類,包括注冊驅動,獲取連接,釋放資源和連接等,這部分同《JDBC操作數據庫的學習(2)》中相同,此處略。

使用Statement對象進行批處理操作:

 1 public void statementbatch() throws SQLException {  2         Connection conn = null;  3         Statement st = null;  4         ResultSet rs = null;  5         
 6         try{  7             conn = JdbcUtils.getConnection();  8             st = conn.createStatement();  9             String sql1 = "insert into batchtest(id,name) values(1,'Ding')"; 10             String sql2 = "update batchtest set name='LRR' where id=1 "; 11 
12  st.addBatch(sql1); 13  st.addBatch(sql2); 14 
15  st.executeBatch(); 16  st.clearBatch(); 17         }finally{ 18  JdbcUtils.release(conn, st, rs); 19  } 20     }
View Code

查看數據庫執行情況:

  

  第一條SQL是插入命令,插入一個id列為1,name列為“Ding”的行數據項;第二條SQL是修改命令,將id列為1的行數據項的name列修改為“LRR”。

例2:使用PreparedStatement對象進行批處理

  因為PreparedStatement對象只能執行相同的操作類型,因此在該案例中我向數據庫中執行插入的批處理SQL。

創建數據庫和表(與例1相同):

create database jdbcdemo; use jdbcdemo; create table batchtest ( id int primary key, name varchar(40) )

創建工程,在工程中導入數據庫連接驅動的jar包。在【src】目錄下新建一個database.properties文件,內容如下:

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/jdbcdemo
    username=root
    password=root

構建JDBC的工具類,包括注冊驅動,獲取連接,釋放資源和連接等,這部分同《JDBC操作數據庫的學習(2)》中相同,此處略。

使用PreparedStatement對象進行批處理操作:

 1 public void preparedStatementBatch() throws SQLException {  2         Connection conn = null;  3         PreparedStatement st = null;  4         ResultSet rs = null;  5         
 6         try{  7             conn = JdbcUtils.getConnection();  8             String sql = "insert into batchtest(id,name) values(?,?)";  9             st = conn.prepareStatement(sql); 10             
11             st.setInt(1, 1);    //設置id列
12             st.setString(2, "Ding");   //設置name列
13  st.addBatch(); 14             
15             st.setInt(1, 2);    //設置id列
16             st.setString(2, "LRR");   //設置name列
17  st.addBatch(); 18             
19  st.executeBatch(); 20  st.clearBatch(); 21         }finally{ 22  JdbcUtils.release(conn, st, rs); 23  } 24     }
View Code

查看數據庫執行情況:

  

  可以看到使用PreparedStatement對象只能對同一條SQL語句中的占位符替代不同參數的批處理操作。

  正是基於這樣的設計,使我們可以利用循環,對一些具有循環性質的替代占位符的參數使用PreparedStatement對象進行批處理,還是上面的例2 ,先清空batchtest表,其他不變,就改變程序為:

 1 public void preparedStatementBatch() throws SQLException {  2         Connection conn = null;  3         PreparedStatement st = null;  4         ResultSet rs = null;  5         
 6         try{  7             conn = JdbcUtils.getConnection();  8             String sql = "insert into batchtest(id,name) values(?,?)";  9             st = conn.prepareStatement(sql); 10             
11             for(int i=1;i<=5;i++) { 12                 st.setInt(1, i);     //設置id列
13                 st.setString(2, "a"+i);   //設置name列
14  st.addBatch(); 15  } 16             
17  st.executeBatch(); 18  st.clearBatch(); 19         }finally{ 20  JdbcUtils.release(conn, st, rs); 21  } 22     }
View Code

查看數據庫執行情況:

  

  對於每次循環,都將在調用addBatch方法后將占位符已經被替代為參數的SQL語句存入PreparedStatement對象中的集合里,在下一次循環就可以進行新的占位符替代並再次存入新的SQL語句,存入SQL語句的次數和循環次數相關,因此如果循環次數過大,那么按上面的例子也將會導致程序內存溢出,解決方法就是將循環次數再分成小的循環批次一批一批地執行。

  

解決:

  

  基本到此就將使用JDBC操作數據庫進行批處理介紹完畢,通常我們會使用PreparedStatement對象的方式多一些,同時最后再說明一點,以上的案例我們都是使用的是MySQL數據庫,對於大數據量的批處理操作,MySQL數據庫的執行相比Oracle數據庫的速度來說還差的很多,因此如果要對數據庫執行大量的批處理操作,建議使用Oracle數據庫。

 

 

 

              


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM