日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【大话Hibernate】hibernate事务管理

發布時間:2024/4/14 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【大话Hibernate】hibernate事务管理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

事務(Transaction)是工作中的基本邏輯單位,可以用于確保數據庫能夠被正確修改,避免數據只修改了一部分而導致數據不完整,或者在修改時受到用戶干擾。 數據庫向用戶提供保存當前程序狀態的方法,叫事務提交(commit);當事務執行過程中,使數據庫忽略當前的狀態并回到前面保存的狀態的方法叫事務回滾(rollback)。


1、事務的特性

事務具備原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)4個屬性,簡稱ACID。下面對這4個特性分別進行說明。
原子性:將事務中所做的操作捆綁成一個原子單元,即對于事務所進行的數據修改等操作,要么全部執行,要么全部不執行。
一致性:事務在完成時,必須使所有的數據都保持一致狀態,而且在相關數據中,所有規則都必須應用于事務的修改,以保持所有數據的完整性。事務結束時,所有的內部數據結構都應該是正確的。
隔離性:由并發事務所做的修改必須與任何其他事務所做的修改相隔離。事務查看數據時數據所處的狀態,要么是被另一并發事務修改之前的狀態,要么是被另一并發事務修改之后的狀態,即事務不會查看由另一個并發事務正在修改的數據。這種隔離方式也叫可串行性。
持久性:事務完成之后,它對系統的影響是永久的,即使出現系統故障也是如此。


2 、事務隔離

事務隔離意味著對于某一個正在運行的事務來說,好像系統中只有這一個事務,其他并發的事務都不存在一樣。在大部分情況下,很少使用完全隔離的事務。但不完全隔離的事務會帶來如下一些問題。

更新丟失(Lost Update):兩個事務都企圖去更新一行數據,導致事務拋出異常退出,兩個事務的更新都白費了。?

臟數據(Dirty Read):如果第二個應用程序使用了第一個應用程序修改過的數據,而這個數據處于未提交狀態,這時就會發生臟讀。第一個應用程序隨后可能會請求回滾被修改的數據,從而導致第二個事務使用的數據被損壞,即所謂的“變臟”。?

不可重讀(Unrepeatable Read):一個事務兩次讀同一行數據,可是這兩次讀到的數據不一樣,就叫不可重讀。如果一個事務在提交數據之前,另一個事務可以修改和刪除這些數據,就會發生不可重讀。?

幻讀(Phantom Read):一個事務執行了兩次查詢,發現第二次查詢結果比第一次查詢多出了一行,這可能是因為另一個事務在這兩次查詢之間插入了新行。針對由事務的不完全隔離所引起的上述問題,提出了一些隔離級別,用來防范這些問題。?

讀操作未提交(Read Uncommitted):說明一個事務在提交前,其變化對于其他事務來說是可見的。這樣臟讀、不可重讀和幻讀都是允許的。當一個事務已經寫入一行數據但未提交,其他事務都不能再寫入此行數據;但是,任何事務都可以讀任何數據。這個隔離級別使用排寫鎖實現。?

讀操作已提交(Read Committed):讀取未提交的數據是不允許的,它使用臨時的共讀鎖和排寫鎖實現。這種隔離級別不允許臟讀,但不可重讀和幻讀是允許的。?

可重讀(Repeatable Read):說明事務保證能夠再次讀取相同的數據而不會失敗。此隔離級別不允許臟讀和不可重讀,但幻讀會出現。?

可串行化(Serializable):提供最嚴格的事務隔離。這個隔離級別不允許事務并行執行,只允許串行執行。這樣,臟讀、不可重讀或幻讀都可發生。


在一個實際應用中,開發者經常不能確定使用什么樣的隔離級別。太嚴厲的級別將降低并發事務的性能,但是不足夠的隔離級別又會產生一些小的Bug,而這些Bug只會在系統重負荷(也就是并發嚴重時)的情況下才會出現。

一般來說,讀操作未提交(Read Uncommitted)是很危險的。一個事務的回滾或失敗都會影響到另一個并行的事務,或者說在內存中留下和數據庫中不一致的數據。這些數據可能會被另一個事務讀取并提交到數據庫中。這是完全不允許的。

另外,大部分程序并不需要可串行化隔離(Serializable Isolation)。雖然,它不允許幻讀,但一般來說,幻讀并不是一個大問題。可串行化隔離需要很大的系統開支,很少有人在實際開發中使用這種事務隔離模式。
現在留下來的可選的隔離級別是讀操作已提交(Read Committed)和可重讀(Repeatable Read)。Hibernate可以很好地支持可重讀(Repeatable Read)隔離級別。


3、在hibernate配置文件中設置隔離級別

hibernate事務隔離級別的數字意義:

1:讀操作未提交(Read Uncommitted)
2:讀操作已提交(Read Committed)
4:可重讀(Repeatable Read)
8:可串行化(Serializable)

設置隔離級別的兩種方式:

1)、在hibernate.properties中設置:hibernate.connection.isolation 42)、在hibernate.cfg.xml中設置:<session-factory>……//把隔離級別設置為4<property name="hibernate.connection.isolation">4</property>…… </session-factory>

在開始一個事務之前,hibernate從配置文件中獲得隔離級別的值。


4、在hibernate中使用JDBC和JTA(Java Transaction API)事務

說明一:Hibernate本身沒有實現自己的事務管理功能,而是對底層JDBC事務或JTA事務的輕量級封裝

hibernate本身沒有實現自己事務管理功能,而是對
底層JDBC事務或JTA事務的輕量級封裝。Hibernate將底層的JDBCTransaction或JTATransaction進行了封裝,再在外面套上Transaction和Session的外殼,其實是通過委托底層的JDBC或JTA來實現事務的處理功能的。


下面我們來通過源碼來看一下hibernate是如何封裝的

org.hibernate.impl.SessionImpl類(該類是會話的實現類):

public Transaction beginTransaction() throws HibernateException {errorIfClosed();if ( rootSession != null ) {log.warn( "Transaction started on non-root session" );}Transaction result = getTransaction();result.begin();return result; }public Transaction getTransaction() throws HibernateException {errorIfClosed();return jdbcContext.getTransaction(); }

org.hibernate.jdbc.JDBCContext類:

public Transaction getTransaction() throws HibernateException {if (hibernateTransaction==null) {hibernateTransaction = owner.getFactory().getSettings().getTransactionFactory().createTransaction( this, owner );}return hibernateTransaction; }

TransactionFactory有很多實現類:

選擇最基本的org.hibernate.transaction.JDBCTransactionFactory觀察一下:

public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)throws HibernateException {return new JDBCTransaction( jdbcContext, transactionContext ); }

org.hibernate.transaction.JDBCTransaction類的說明:

Transaction implementation based on transaction management through a JDBC Connection. This the Hibernate’s default transaction strategy.

事務開始時會禁用自動提交:

public void begin() throws HibernateException {if (begun) {return;}if (commitFailed) {throw new TransactionException("cannot re-start transaction after failed commit");}log.debug("begin");try {toggleAutoCommit = jdbcContext.connection().getAutoCommit();if ( log.isDebugEnabled() ) {log.debug("current autocommit status: " + toggleAutoCommit);}if (toggleAutoCommit) {log.debug("disabling autocommit");jdbcContext.connection().setAutoCommit(false);//關閉事務自動提交}}catch (SQLException e) {log.error("JDBC begin failed", e);throw new TransactionException("JDBC begin failed: ", e);}callback = jdbcContext.registerCallbackIfNecessary();begun = true;committed = false;rolledBack = false;if ( timeout>0 ) {jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);}jdbcContext.afterTransactionBegin(this); }

通過日志也能看出一點東西:

[2013-08-09 16:37:55] DEBUG -> begin [2013-08-09 16:37:55] DEBUG -> opening JDBC connection [2013-08-09 16:37:55] DEBUG -> current autocommit status: false [2013-08-09 16:37:55] DEBUG -> generated identifier: 1, using strategy: org.hibernate.id.Assigned [2013-08-09 16:37:55] DEBUG -> commit

說明二:不需要顯式的調用flush()方法,事務提交時會根據session的FlushMode自動觸發session的flush

還是通過最基本的JDBCTransaction類看一下:

事務提交完成之后又恢復了事務的自動提交:

public void commit() throws HibernateException {if (!begun) {throw new TransactionException("Transaction not successfully started");}log.debug("commit");if ( !transactionContext.isFlushModeNever() && callback ) {transactionContext.managedFlush(); //根據FlushMode(通常為AUTO)刷新SessionnotifySynchronizationsBeforeTransactionCompletion();if ( callback ) {jdbcContext.beforeTransactionCompletion( this );}try {commitAndResetAutoCommit();//在該方法中重新開啟了事務自動提交log.debug("committed JDBC Connection");committed = true;if ( callback ) {jdbcContext.afterTransactionCompletion( true, this );}notifySynchronizationsAfterTransactionCompletion( Status.STATUS_COMMITTED );}catch (SQLException e) {log.error("JDBC commit failed", e);commitFailed = true;if ( callback ) {jdbcContext.afterTransactionCompletion( false, this );}notifySynchronizationsAfterTransactionCompletion( Status.STATUS_UNKNOWN );throw new TransactionException("JDBC commit failed", e);}finally {closeIfRequired();} }private void commitAndResetAutoCommit() throws SQLException {try {jdbcContext.connection().commit();}finally {toggleAutoCommit();} }private void toggleAutoCommit() {try {if (toggleAutoCommit) {log.debug("re-enabling autocommit");jdbcContext.connection().setAutoCommit( true );//重新開啟事務自動提交}}catch (Exception sqle) {log.error("Could not toggle autocommit", sqle);//swallow it (the transaction _was_ successful or successfully rolled back)} }

JDBC事務默認自動提交,但是如果Hibernate的事務策略使用JDBC,在事務開始之前,Hibernate會關閉事務自動提交,在事務結束之后,重新開啟事務自動提交


5、 在Hibernate中使用JDBC事務

Hibernate對JDBC進行了輕量級的封裝,它本身在設計時并不具備事務處理功能。Hibernate將底層的JDBCTransaction或JTATransaction進行了封裝,再在外面套上Transaction和Session的外殼,其實是通過委托底層的JDBC或JTA來實現事務的處理功能的。

要在Hibernate中使用事務,可以在它的配置文件中指定使用JDBCTransaction或者JTATransaction。在hibernate.properties中,查找“transaction.factory_class”關鍵字,得到以下配置:

# hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory # hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory

Hibernate的事務工廠類可以設置成JDBCTransactionFactory或者JTATransactionFactory。如果不進行配置,Hibernate就會認為系統使用的事務是JDBC事務。

在JDBC的提交模式(commit mode)中,如果數據庫連接是自動提交模式(auto commit mode),那么在每一條SQL語句執行后事務都將被提交,提交后如果還有任務,那么一個新的事務又開始了。

Hibernate在Session控制下,在取得數據庫連接后,就立刻取消自動提交模式,即Hibernate在一個執行Session的beginTransaction()方法后,就自動調用JDBC層的setAutoCommit(false)。如果想自己提供數據庫連接并使用自己的SQL語句,為了實現事務,那么一開始就要把自動提交關掉(setAutoCommit(false)),并在事務結束時提交事務。

使用JDBC事務是進行事務管理最簡單的實現方式,Hibernate對于JDBC事務的封裝也很簡單。下面是一個在Hibernate中使用JDBC事務的例子:

try { Session session = HibernateUtil.currentSession();Transaction tx = session.beginTransaction(); //在默認情況下,開啟一個JDBC事物 for(int i=0; i<10; i++) { Student stu = new Student(); stu.setName("Student" + i); session.save(stu); } tx.commit(); //提交事務 session.close(); } catch(Exception e) {… tx.rollback(); //事務回滾 }

6、 在Hibernate中使用JTA事務

JTA(Java Transaction API)是事務服務的J2EE解決方案。本質上,它是描述事務接口的J2EE模型的一部分,開發人員直接使用該接口或者通過J2EE容器使用該接口來確保業務邏輯能夠可靠地運行。

JTA有3個接口,它們分別是UserTransaction接口、TransactionManager接口和Transaction接口。這些接口共享公共的事物操作,例如commit()和rollback(),但也包含特殊的事務操作,例如suspend()、resume()和enlist(),它們只出現在特定的接口上,以便在實現中允許一定程度的訪問控制。

在一個具有多個數據庫的系統中,可能一個程序會調用幾個數據庫中的數據,需要一種分布式事務,或者準備用JTA來管理跨Session的長事務,那么就需要使用JTA事務。下面介紹如何在Hibernate的配置文件中配置JTA事務。在hibernate.properties文件中設置如下(把JTATransactionFactory所在的配置行的注釋符“#”取消掉):

#hibernate.transaction.factory_classorg.hibernate.transaction.JTATransactionFactory # hibernate.transaction.factory_classorg.hibernate.transaction.JDBCTransactionFactory

或者在hibernate.cfg.xml文件中配置如下:

<session-factory><property name= hibernate.transaction.factory_class”> org.hibernate.transaction.JTATransactionFactory </property></session-factory>

下面是一個應用JTA事務的例子:

javax.transaction.UserTransaction tx = null; tx = new initialContext().lookup(” javax.transaction.UserTransaction ”) ; tx.begin(); Session s1 = sf.openSession(); …… s1.flush(); s1.close(); Session s2 = sf.openSession(); …… s2.flush(); s2.close(); tx.commit();

總結

以上是生活随笔為你收集整理的【大话Hibernate】hibernate事务管理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。