在我們做.net系統的時候,所做的最常見的批量操作就是批量導入、插入、更新、刪除等等,以前我們怎么做呢?基本上有以下幾種方式:
1、利用循環調用insert方法,一條條插入。
- public boolean insertStudent(List<Student> studentList)
- {
- try{
- if(studentList.count !=0){
- for(int i=0;i<studentList.count;i++){
-
- }
- return true;
- }
- }catch(Exception ex){
- throw New Exception("插入失敗,請重試!")
- return false;
- }
- }
2、利用循環做sql語句拼接,然后批量執行sql語句。
- public boolean insertStudent(List<Student> studentList)
- {
- try{
- if(studentList.count !=0){
- stringBuffer strSqltxt="";
- for(int i=0;i<studentList.count;i++){
- strSqltxt.append("insert into TableName (……) values (……);"
- }
- cmd.executesql(strSqltxt.toString());
- }
- }catch(Exception ex){
- throw New Exception("插入失敗,請重試!")
- return false;
- }
- }
可是,對於封裝比較完善的hibernate持久層,我們又能怎么做呢?
最常見的,也是利用循環來批量操作,但是,這里有一個必須要注意的點,就是緩存或者說是session區的空間是有限的,禁不起我們無限制的存放,所以,當我們執行以下操作時,會拋異常,內存溢出OutOfMemoryException!
- Session session = sessionFactory.openSession();
- Transaction tx = session.beginTransaction();
- for ( int i=0; i<100000; i++ ) {
- Customer customer = new Customer(.....);
- session.save(customer);
- }
- tx.commit();
- session.close();
這樣是不可以的,但是在這時,hibernate也給我們提供了解決方法,就是我們可以通過設置JDBC的批量抓去數量參數(batch size)來設置一個合適的值,比如說10-50-100不等,配置:
- <span style="font-size:18px;"><property name="hibernate.jdbc.batch_size">100</property></span>
另外,我們還可以顯示的禁用二級緩存,以前我們也提到過:
<property name="hibernate.cache.use_second_level_cache">false</property>
正確代碼:
- Session session = sessionFactory.openSession();
- Transaction tx = session.beginTransaction();
- for ( int i=0; i<100000; i++ ) {
- Customer customer = new Customer(.....);
- session.save(customer);
- if(i%100==0){
- session.fulsh();
- session.clear();
- }
- }
- tx.commit();
- 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相當接近。換句話說,它可以直接操作數據。
- StatelessSession session = sessionFactory.openStatelessSession();
- Transaction tx = session.beginTransaction();
-
- ScrollableResults customers = session.getNamedQuery("GetCustomers")
- .scroll(ScrollMode.FORWARD_ONLY);
- while ( customers.next() ) {
- Customer customer = (Customer) customers.get(0);
- customer.updateStuff(...);
- session.update(customer);
- }
-
- tx.commit();
- session.close();
DML(Data Manipulation Language數據操作語言)風格操作
再有就是特殊服務(業務需求)需要我們采用DML(Data Manipulation Language數據操作語言)風格操作,從一張表導入另一張表數據,比方說從學生表(T_Studeng)里面往大三學生表(T_ThreeStudent)里面倒數據.
- Session session = sessionFactory.openSession();
- Transaction tx = session.beginTransaction();
-
- String hqlInsert = "insert into ThreeStudent(id, name) select s.id, s.name from Student s where ...";
- int createdEntities = s.createQuery( hqlInsert )
- .executeUpdate();
- tx.commit();
- session.close();
以上就是對批量操作的一點總結,萬望對大家能有點幫助