在我們的Java項目中批量更新是指在一個事務中更新大批量數據批量刪除是指在一個事務中刪除大批量數據批量刪除雖然在Hibernate裡也可以實現但因Hibernate的實現機制是一個一個刪除在數量大的情況下很影響效率;其實Hibernate提供的JDBC接口可以方便的進行批量的更新和刪除
以下程序直接通過Hibernate API批量更新CUSTOMERS表中年齡大於零的所有記錄的AGE字段
tx = sessionbeginTransaction();
Iterator customers=sessionfind(from Customer c where cage>erator();
while(customershasNext()){Customer customer=(Customer)customersnext();
customersetAge(customergetAge()+);
}
mit();
sessionclose();
如果CUSTOMERS表中有萬條年齡大於零的記錄那麼Session的find()方法會一下子加載萬個Customer對象到內存當執行mit()方法時會清理緩存Hibernate執行萬條更新CUSTOMERS表的update語句
update CUSTOMERS set AGE=? … where ID=i;
update CUSTOMERS set AGE=? … where ID=j;
……
update CUSTOMERS set AGE=? … where ID=k;
以上批量更新方式有兩個缺點
()占用大量內存必須把萬個Customer對象先加載到內存然後一一更新它們
()執行的update語句的數目太多每個update語句只能更新一個Customer對象必須通過萬條update語句才能更新一萬個Customer對象頻繁的訪問數據庫會大大降低應用的性能
為了迅速釋放萬個Customer對象占用的內存可以在更新每個Customer對象後就調用Session的evict()方法立即釋放它的內存
tx = sessionbeginTransaction();
Iterator customers=sessionfind(from Customer c where cage>erator();
while(customershasNext()){Customer customer=(Customer)customersnext();
customersetAge(customergetAge()+);
sessionflush();sessionevict(customer);
}
mit();sessionclose();
在以上程序中修改了一個Customer對象的age屬性後就立即調用Session的flush()方法和evict()方法flush()方法使Hibernate立刻根據這個Customer對象的狀態變化同步更新數據庫從而立即執行相關的update語句;evict()方法用於把這個Customer對象從緩存中清除出去從而及時釋放它占用的內存
但evict()方法只能稍微提高批量操作的性能因為不管有沒有使用evict()方法Hibernate都必須執行萬條update語句才能更新萬個Customer對象這是影響批量操作性能的重要因素假如Hibernate能直接執行如下SQL語句
update CUSTOMERS set AGE=AGE+ where AGE>;
那麼以上一條update語句就能更新CUSTOMERS表中的萬條記錄但是Hibernate並沒有直接提供執行這種update語句的接口應用程序必須繞過Hibernate API直接通過JDBC API來執行該SQL語句
tx = sessionbeginTransaction();
Connection con=nnection();
PreparedStatement stmt=conprepareStatement(update CUSTOMERS set AGE=AGE+ +where AGE> );stmtexecuteUpdate();
mit();
以上程序演示了繞過Hibernate API直接通過JDBC API訪問數據庫的過程應用程序通過Session的connection()方法獲得該Session使用的數據庫連接然後通過它創建PreparedStatement對象並執行SQL語句值得注意的是應用程序仍然通過Hibernate的Transaction接口來聲明事務邊界
如果底層數據庫(如Oracle)支持存儲過程也可以通過存儲過程來執行批量更新存儲過程直接在數據庫中運行速度更加快在Oracle數據庫中可以定義一個名為batchUpdateCustomer()的存儲過程代碼如下
create or replace procedure batchUpdateCustomer(p_age in number)
asbeginupdate CUSTOMERS
set AGE=AGE+ where AGE>p_age;
end;
以上存儲過程有一個參數p_age代表客戶的年齡應用程序可按照以下方式調用存儲過程
tx = sessionbeginTransaction();
Connection con=nnection();
String procedure = {call batchUpdateCustomer(?) };
CallableStatement cstmt = conprepareCall(procedure);cstmtsetInt(); //把年齡參數設為cstmtexecuteUpdate();
mit();
從上面程序看出應用程序也必須繞過Hibernate API直接通過JDBC API來調用存儲過程
Session的各種重載形式的update()方法都一次只能更新一個對象而delete()方法的有些重載形式允許以HQL語句作為參數例如
sessiondelete(from Customer c where cage>);
如果CUSTOMERS表中有萬條年齡大於零的記錄那麼以上代碼能刪除一萬條記錄但是Session的delete()方法並沒有執行以下delete語句
delete from CUSTOMERS where AGE>;
Session的delete()方法先通過以下select語句把萬個Customer對象加載到內存中
select * from CUSTOMERS where AGE>;
接下來執行一萬條delete語句逐個刪除Customer對象
delete from CUSTOMERS where ID=i;
delete from CUSTOMERS where ID=j;
……
delete from CUSTOMERS where ID=k;
由此可見直接通過Hibernate API進行批量更新和批量刪除都不值得推薦而直接通過JDBC API執行相關的SQL語句或調用相關的存儲過程是批量更新和批量刪除的最佳方式這兩種方式都有以下優點
()無需把數據庫中的大批量數據先加載到內存中然後逐個更新或修改它們因此不會消耗大量內存
()能在一條SQL語句中更新或刪除大批量的數據
From:http://tw.wingwit.com/Article/program/Java/ky/201311/27864.html