全局事務與本地事務的區別應用

全局事務:資源管理器管理和協調的事務,可以跨越多個數據庫和進程。資源管理器一般使用 XA 二階段提交協議與“企業信息系統”(EIS) 或數據庫進行交互。
本地事務:在單個 EIS 或數據庫的本地並且限制在單個進程內的事務。本地事務不涉及多個數據來源。

在Hibernate配置文件中有這麼兩種配置方式:

1.如果使用的是本地事務(jdbc事務)
<property name="hibernate.current_session_context_class">thread</property>,這個是我們常用的選項,只針對一個數據庫進行操作,也就是說只針對一個事務性資源進行操作.
2. 如果使用的是全局事務(jta事務)
<property name="hibernate.current_session_context_class">jta</property>   

    以前我們學習的事務類型都屬於本地事務。 JTA(全局事務)和thread(本地事務)有什麼區別呢?在某些應用場合,只能使用全局事務,比如:
有兩個數據庫:
1.mysql 2.oracle  現在有個業務需求--轉賬
step 1> update mysql_table set amount=amount-xx where id=aaa 發生扣錢,假設是在mysql數據庫扣錢的。
step 2> update oracle_table set amount=amount+xx where id=bbb 加錢,假設是在oracle數據庫扣錢的。
現在怎麼確保兩個語句在同一個事務裏執行呢?

以前在JDBC裏是這樣做
connection = mysql 連接mysql
connection.setAutoCommit(false);  不自動提交
1> update mysql_table set amount=amount-xx where id=aaa 發生扣錢,假設是在mysql數據庫扣錢的。
2> update oracle_table set amount=amount+xx where id=bbb  發生在oracle數據庫
connection.commit();
執行這兩條語句,然後通過connection對象提交事務.我們這樣子做只能確保這兩個語句在同一個數據庫mysql裏面實現在同一個事務裏執行。 但是問題是我們現在是要連接到oracle數據庫,是不是需要connection2啊?

connection = mysql 連接mysql
connection2 = oracle 連接oracle
connection.setAutoCommit(false);  不自動提交
1> update mysql_table set amount=amount-xx where id=aaa 發生扣錢,假設是在mysql數據庫扣錢的。
2> update oracle_table set amount=amount+xx where id=bbb  發生在oracle數據庫
connection.commit();
connection2.setAutoCommit(false);
connection2.commit();
事務只能在一個connection裏打開,並且確保兩條語句都在該connection裏執行,這樣才能讓兩條語句在同一事務裏執行,現在問題就在於connection2是連接到oracle數據庫的,那麼connection2再開事務有意義嗎?它能確保嗎?不能,所以在這種情況下就只能使用全局事務了。
這種情況下用普通JDBC操作是滿足不了這個業務需求的,這種業務需求只能使用全局事務,本地事務是無法支持我們的操作的,因爲這時候,事務的生命週期不應該侷限於connection對象的生命週期範圍

全局事務怎麼做呢?
JPA.getUserTransaction().begin();      首先要全局事務的API,不需要我們編寫,通常容器已經提供給我們了,我們只需要begin一下
connection = mysql 連接mysql
connection2 = oracle 連接oracle
connection--> update mysql_table set amount=amount-xx where id=aaa 發生扣錢,假設是在mysql數據庫扣錢的。
connection2--> update oracle_table set amount=amount+xx where id=bbb 發生在oracle數據庫
JPA.getUserTransaction().commit();

那麼它是怎麼知道事務該提交還是回滾呢?
這時候它使用了二次提交協議。二次提交協議簡單說就這樣:如果你先執行第一條語句,執行的結果先預提交到數據庫,預提交到數據庫了,數據庫會執行這條語句,然後返回一個執行的結果,這個結果假如我們用布爾值表示的話,成功就是true,失敗就是false.然後把執行的結果放入一個(假設是List)對象裏面去,接下來再執行第二條語句,執行完第二條語句之後(也是預處理,數據庫不會真正實現數據的提交,只是說這條語句送到數據庫裏面,它模擬下執行,給你返回個執行的結果),假如這兩條語句的執行結果在List裏面都是true的話,那麼這個事務就認爲語句是成功的,這時候全局事務就會提交。二次提交協議,數據庫在第一次提交這個語句時,只會做預處理,不會發生真正的數據改變,當我們在全局事務提交的時候,這時候發生了第二次提交,那麼第二次提交的時候纔會真正的發生數據的改動。
   如果說在執行這兩條語句中,有一個出錯了,那麼List集合裏就有個元素爲false,那麼全局事務就認爲你這個事務是失敗的,它就會進行回滾,回滾的時候,哪怕你的第二條語句在第一次提交的時候是成功的,它在第二次提交的時候也會回滾,那麼第一次的更改也會恢復到之前的狀態,這就是二次提交協議。(可以查看一下數據庫方面的文檔來了解二次提交協議)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章