【Hibernate框架】批量操作Batch總結


在我們做.net系統的時候,所做的最常見的批量操作就是批量導入、插入、更新、刪除等等,以前我們怎么做呢?基本上有以下幾種方式:

1、利用循環調用insert方法,一條條插入。

 

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public boolean insertStudent(List<Student> studentList)  
  2. {  
  3.     try{  
  4.         if(studentList.count !=0){  
  5.             for(int i=0;i<studentList.count;i++){  
  6.                 //調用save方法  
  7.             }  
  8.                 return true;  
  9.                 }  
  10.     }catch(Exception ex){  
  11.         throw New Exception("插入失敗,請重試!")  
  12.         return false;  
  13.     }  
  14. }  



 


2、利用循環做sql語句拼接,然后批量執行sql語句。

 

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public boolean insertStudent(List<Student> studentList)  
  2. {  
  3.     try{  
  4.         if(studentList.count !=0){  
  5.             stringBuffer strSqltxt="";  
  6.             for(int i=0;i<studentList.count;i++){  
  7.                 strSqltxt.append("insert into TableName (……) values (……);"  
  8.             }  
  9.             cmd.executesql(strSqltxt.toString());  
  10.         }  
  11.     }catch(Exception ex){  
  12.         throw New Exception("插入失敗,請重試!")  
  13.         return false;  
  14.     }  
  15. }  



 

可是,對於封裝比較完善的hibernate持久層,我們又能怎么做呢?

       

       最常見的,也是利用循環來批量操作,但是,這里有一個必須要注意的點,就是緩存或者說是session區的空間是有限的,禁不起我們無限制的存放,所以,當我們執行以下操作時,會拋異常,內存溢出OutOfMemoryException!

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. Session session = sessionFactory.openSession();  
  2. Transaction tx = session.beginTransaction();  
  3. for ( int i=0; i<100000; i++ ) {  
  4.     Customer customer = new Customer(.....);  
  5.     session.save(customer);  
  6. }  
  7. tx.commit();  
  8. session.close();  


這樣是不可以的,但是在這時,hibernate也給我們提供了解決方法,就是我們可以通過設置JDBC的批量抓去數量參數(batch size)來設置一個合適的值,比如說10-50-100不等,配置:

 

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:18px;"><property name="hibernate.jdbc.batch_size">100</property></span>  

 

 

另外,我們還可以顯示的禁用二級緩存,以前我們也提到過:

<property name="hibernate.cache.use_second_level_cache">false</property>

 

正確代碼:

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. Session session = sessionFactory.openSession();  
  2. Transaction tx = session.beginTransaction();  
  3. for ( int i=0; i<100000; i++ ) {  
  4.     Customer customer = new Customer(.....);  
  5.     session.save(customer);  
  6.     if(i%100==0){//100, 和配置的JDBC batch size一樣  
  7.         session.fulsh();//刷出並同步到底層持久化, 批量的插入並且釋放內存:  
  8.         session.clear(); //完全清除session  
  9.     }  
  10. }  
  11. tx.commit();  
  12. session.close();  

 

這樣就能解決我們的那個內存溢出的問題,因為當你的存儲對象數超過你設定的能接受的合理值的時候,程序會自動將持久化對象flush進數據緩存起來,然后清空session,進行下一輪存儲,待所有數據全部完成,執行commit進行提交,數據庫更新數據,說的簡單,這樣的效率是不咋地的,不信你可以試試,你想想,先發出sql,100一輪,執行1000輪用來緩存sql語句,然后數據庫統一執行sql,時間啊!

 

StatelessSession(無狀態session)接口

但是這不是問題,因為hibernate還給我們提供了一個StatelessSession(無狀態session)接口,作為選擇,Hibernate提供了基於命令的API:

1、可以用detached object(托管對象)的形式把數據以流的方法加入到數據庫,或從數據庫輸出。

2、StatelessSession沒有持久化上下文,也不提供多少高層的生命周期語義。

3、無狀態session不實現第一級cache;

4、也不和第二級緩存交互,也不和查詢緩存交互。

5、它不實現事務化寫,也不實現臟數據檢查。

6、用stateless session進行的操作甚至不級聯到關聯實例。

7、stateless session忽略集合類(Collections)。

8、通過stateless session進行的操作不觸發Hibernate的事件模型和攔截器。

9、無狀態session對數據的混淆現象免疫,因為它沒有第一級緩存。

10、無狀態session是低層的抽象,和低層JDBC相當接近。換句話說,它可以直接操作數據。

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. StatelessSession session = sessionFactory.openStatelessSession();  
  2. Transaction tx = session.beginTransaction();  
  3.      
  4. ScrollableResults customers = session.getNamedQuery("GetCustomers")  
  5.     .scroll(ScrollMode.FORWARD_ONLY);  
  6. while ( customers.next() ) {  
  7.     Customer customer = (Customer) customers.get(0);  
  8.     customer.updateStuff(...);  
  9.     session.update(customer);  
  10. }  
  11.      
  12. tx.commit();  
  13. session.close();  

 

 

DML(Data Manipulation Language數據操作語言)風格操作

再有就是特殊服務(業務需求)需要我們采用DML(Data Manipulation Language數據操作語言)風格操作,從一張表導入另一張表數據,比方說從學生表(T_Studeng)里面往大三學生表(T_ThreeStudent)里面倒數據.

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. Session session = sessionFactory.openSession();  
  2. Transaction tx = session.beginTransaction();  
  3.   
  4. String hqlInsert = "insert into ThreeStudent(id, name) select s.id, s.name from Student s where ...";  
  5. int createdEntities = s.createQuery( hqlInsert )  
  6.         .executeUpdate();  
  7. tx.commit();  
  8. session.close();  

 

 

以上就是對批量操作的一點總結,萬望對大家能有點幫助


免責聲明!

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



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