什麼是事務?java
事務(Transaction),通常是指要作的或所作的事情。在計算機術語中是指訪問並可能更新數據庫中各類數據項的一個程序執行單元(unit)。事務一般由高級數據庫操縱語言或編程語言(如SQL,C++或Java)書寫的用戶程序的執行所引發,並用形如begin transaction和end transaction語句(或函數調用)來界定。事務由事務開始(begin transaction)和事務結束(end transaction)之間執行的全體操做組成。mysql
爲何要事務?spring
事務是爲解決數據安全操做提出的,事務控制實際上就是控制數據的安全訪問。sql
用一個簡單例子說明:銀行轉賬業務,帳戶A要將本身帳戶上的1000元轉到B帳戶下面,A帳戶餘額首先要減去1000元,而後B帳戶要增長1000元。假如在中間網絡出現了問題,A帳戶減去1000元已經結束,B由於網絡中斷而操做失敗,那麼整個業務失敗,必須作出控制,要求A帳戶轉賬業務撤銷。這才能保證業務的正確性,完成這個操走就須要事務,將A帳戶資金減小和B帳戶資金增長放到同一個事務裏,要麼所有執行成功,要麼所有撤銷,這樣就保證了數據的安全性。數據庫
事務的4個特性(ACID):編程
1) 原子性(atomicity):事務是數據庫的邏輯工做單位,並且是必須是原子工做單位,對於其數據修改,要麼所有執行,要麼所有不執行。後端
2) 一致性(consistency):事務在完成時,必須是全部的數據都保持一致狀態。在相關數據庫中,全部規則都必須應用於事務的修改,以保持全部數據的完整性。(實例:轉帳,兩個帳戶餘額相加,值不變。)安全
3) 隔離性(isolation):一個事務的執行不能被其餘事務所影響。服務器
4) 持久性(durability):一個事務一旦提交,事物的操做便永久性的保存在DB中。即使是在數據庫系統遇到故障的狀況下也不會丟失提交事務的操做。網絡
Java有幾種類型的事務?
Java事務的類型有三種:JDBC事務、JTA(Java Transaction API)事務、容器事務。
1.JDBC事務
在JDBC中處理事務,都是經過Connection完成的。同一事務中全部的操做,都在使用同一個Connection對象。JDBC事務默認是開啓的,而且是默認提交。
JDBC Connection 接口提供了兩種事務模式:自動提交和手工提交
JDBC中的事務java.sql.Connection 的三個方法與事務有關:
setAutoCommit(boolean):設置是否爲自動提交事務,若是true(默認值爲true)表示自動提交,也就是每條執行的SQL語句都是一個單獨的事務,若是設置爲false,須要手動提交事務。
commit():提交結束事務。
rollback():回滾結束事務。
傳統JDBC操做流程:
1).獲取JDBC鏈接 2).聲明SQL 3).預編譯SQL 4).執行SQL 5).處理結果集
6).釋放結果集 7).釋放Statement 8).提交事務 9).處理異常並回滾事務 10).釋放JDBC鏈接
JDBC優缺點:1.冗長、重複 2.顯示事務控制 3.每一個步驟不可獲取 4.顯示處理受檢查異常
JDBC爲使用Java進行數據庫的事務操做提供了最基本的支持。經過JDBC事務,咱們能夠將多個SQL語句放到同一個事務中,保證其ACID特性。JDBC事務的主要優勢就是API比較簡單,能夠實現最基本的事務操做,性能也相對較好。可是,JDBC事務有一個侷限:一個 JDBC 事務不能跨越多個數據庫!因此,若是涉及到多數據庫的操做或者分佈式場景,JDBC事務就無能爲力了。
2.JTA事務
JTA(Java Transaction API)提供了跨數據庫鏈接(或其餘JTA資源)的事務管理能力。JTA事務管理則由JTA容器實現,J2ee框架中事務管理器與應用程序,資源管理器,以及應用服務器之間的事務通信。
1)JTA的構成
a、高層應用事務界定接口,供事務客戶界定事務邊界的
b、X/Open XA協議(資源之間的一種標準化的接口)的標準Java映射,它可使事務性的資源管理器參與由外部事務管理器控制的事務中
c、高層事務管理器接口,容許應用程序服務器爲其管理的應用程序界定事務的邊界
2)JTA的主要接口位於javax.transaction包中
a、UserTransaction接口:讓應用程序得以控制事務的開始、掛起、提交、回滾等。由Java客戶端程序或EJB調用。
b、TransactionManager 接口:用於應用服務器管理事務狀態
c、Transaction接口:用於執行相關事務操做
d、XAResource接口:用於在分佈式事務環境下,協調事務管理器和資源管理器的工做
e、Xid接口:爲事務標識符的Java映射
注:前3個接口位於Java EE版的類庫 javaee.jar 中,Java SE中沒有提供!UserTransaction是編程經常使用的接口,JTA只提供了接口,沒有具體的實現。
JTS(Java Transaction Service)是服務OTS的JTA的實現。簡單的說JTS實現了JTA接口,而且符合OTS的規範。
JTA的事務週期可橫跨多個JDBC Connection生命週期,對衆多Connection進行調度,實現其事務性要求。
JTA能夠處理任何提供符合XA接口的資源。包括:JDBC鏈接,數據庫,JMS,商業對象等等。
3)JTA編程的基本步驟
a、首先配置JTA ,創建相應的數據源
b、創建事務:經過建立UserTransaction類的實例來開始一個事務。代碼以下:
Context ctx = new InitialContext(p) ;
UserTransaction trans = (UserTransaction) ctx.lookup("javax. Transaction.UserTransaction")
c、開始事務:代碼爲 trans.begin() ;
d、找出數據源:從Weblogic Server上找到數據源,代碼以下:
DataSource ds = (DataSource) ctx.lookup(「mysqldb") ;
e、創建數據庫鏈接:Connection mycon = ds.getConnection() ;
f、執行SQL操做:stmt.executeUpdate(sqlS);
g、完成事務:trans.commit(); / trans.rollback();
h、關閉鏈接:mycon.close() ;
JTA的優缺點:
JTA的優勢很明顯,就是提供了分佈式事務的解決方案,嚴格的ACID。可是,標準的JTA方式的事務管理在平常開發中並不經常使用。
JTA的缺點是實現複雜,一般狀況下,JTA UserTransaction須要從JNDI獲取。這意味着,若是咱們使用JTA,就須要同時使用JTA和JNDI。
JTA自己就是個笨重的API,一般JTA只能在應用服務器環境下使用,所以使用JTA會限制代碼的複用性。
三、Spring容器事務
Spring事務管理的實現有許多細節,若是對整個接口框架有個大致瞭解會很是有利於咱們理解事務,下面經過講解Spring的事務接口來了解Spring實現事務的具體策略。
Spring事務管理涉及的接口及其聯繫:
Spring並不直接管理事務,而是提供了多種事務管理器,他們將事務管理的職責委託給Hibernate或者JTA等持久化機制所提供的相關平臺框架的事務來實現。 Spring事務管理器的接口是org.springframework.transaction.PlatformTransactionManager,經過這個接口,Spring爲各個平臺如JDBC、Hibernate等都提供了對應的事務管理器,可是具體的實現就是各個平臺本身的事情了。
Public interface PlatformTransactionManager{
// 由TransactionDefinition獲得TransactionStatus對象
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 提交
Void commit(TransactionStatus status) throws TransactionException;
// 回滾
Void rollback(TransactionStatus status) throws TransactionException;
}
1)、Spring JDBC事務
若是應用程序中直接使用JDBC來進行持久化,DataSourceTransactionManager會爲你處理事務邊界。爲了使用 DataSourceTransactionManager,你須要使用以下的XML將其裝配到應用程序的上下文定義中:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
實際上,DataSourceTransactionManager是經過調用java.sql.Connection來管理事務。經過調用鏈接的commit()方法來提交事務,一樣,事務失敗則經過調用rollback()方法進行回滾。
2)、Hibernate事務
若是應用程序的持久化是經過Hibernate實現的,那麼你須要使用HibernateTransactionManager。對於Hibernate3,須要在Spring上下文定義中添加以下的<bean>聲明:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
sessionFactory屬性須要裝配一個Hibernate的session工廠,HibernateTransactionManager的實現細節是它將事務管理的職責委託給org.hibernate.Transaction對象,然後者是從Hibernate Session中獲取到的。當事務成功完成時,HibernateTransactionManager將會調用Transaction對象的commit()方法,反之,將會調用rollback()方法。
3)、Java持久化API事務(JPA)
Hibernate多年來一直是事實上的Java持久化標準,可是如今Java持久化API做爲真正的Java持久化標準進入你們的視野。若是你計劃使用JPA的話,那你須要使用Spring的JpaTransactionManager來處理事務。你須要在Spring中這樣配置JpaTransactionManager:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
JpaTransactionManager只須要裝配一個JPA實體管理工廠(javax.persistence.EntityManagerFactory接口的任意實現)。JpaTransactionManager將與由工廠所產生的JPA EntityManager合做來構建事務。
基本的事務屬性的定義:
事務管理器接口PlatformTransactionManager經過getTransaction(TransactionDefinition definition)方法來獲得事務,這個方法裏面的參數是TransactionDefinition類,這個類就定義了一些基本的事務屬性。
事務屬性能夠理解成事務的一些基本配置,描述了事務策略如何應用到方法上。
事務屬性包含了5個方面:
傳播行爲、隔離規則、回滾規則、事務超時、是否只讀
TransactionDefinition:
public interface TransactionDefinition {
int getPropagationBehavior(); // 返回事務的傳播行爲
int getIsolationLevel(); // 返回事務的隔離級別,事務管理器根據它來控制另一個事務能夠看到本事務內的哪些數據
int getTimeout(); // 返回事務必須在多少秒內完成
boolean isReadOnly(); // 事務是否只讀,事務管理器可以根據這個返回值進行優化,確保事務是隻讀的
}
7種傳播行爲:
PROPAGATION_REQUIRED:若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。這是最多見的選擇。
PROPAGATION_SUPPORTS:支持當前事務,若是當前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY:支持當前事務,若是當前沒有事務,就拋出異常。
PROPAGATION_REQUIRES_NEW:新建事務,若是當前存在事務,把當前事務掛起。
PROPAGATION_NOT_SUPPORTED:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER:以非事務方式執行,若是當前存在事務,則拋出異常。
雖然有7種,可是經常使用的就第一種REQUIRED和第四種REQUIRES_NEW
五個隔離級別:
ISOLATION_DEFAULT:這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.
另外四個與JDBC的隔離級別相對應;
ISOLATION_READ_UNCOMMITTED:這是事務最低的隔離級別,它充許別外一個事務能夠看到這個事務未提交的數據。
這種隔離級別會產生髒讀,不可重複讀和幻像讀。
ISOLATION_READ_COMMITTED:保證一個事務修改的數據提交後才能被另一個事務讀取。另一個事務不能讀取該事務未提交的數據。
這種事務隔離級別能夠避免髒讀出現,可是可能會出現不可重複讀和幻像讀。
ISOLATION_REPEATABLE_READ:這種事務隔離級別能夠防止髒讀,不可重複讀。可是可能出現幻像讀。
它除了保證一個事務不能讀取另外一個事務未提交的數據外,還保證了避免下面的狀況產生(不可重複讀)。
ISOLATION_SERIALIZABLE:這是花費最高代價可是最可靠的事務隔離級別。事務被處理爲順序執行。
除了防止髒讀,不可重複讀外,還避免了幻像讀。
事務的屬性可同經過註解方式或配置文件配置:
註解方式:
@Transactional只能被應用到public方法上,對於其它非public的方法,若是標記了@Transactional也不會報錯,但方法沒有事務功能.
默認狀況下,一個有事務方法, 遇到RuntimeException 時會回滾 . 遇到 受檢查的異常 是不會回滾 的. 要想全部異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常})
@Transactional(
readOnly = false, //讀寫事務
timeout = -1 , //事務的超時時間,-1爲無限制
noRollbackFor = ArithmeticException.class, //遇到指定的異常不回滾
isolation = Isolation.DEFAULT, //事務的隔離級別,此處使用後端數據庫的默認隔離級別
propagation = Propagation.REQUIRED //事務的傳播行爲
)
配置文件( aop攔截器方式):
<tx:advice id="advice" transaction-manager="txManager"> <tx:attributes> <!-- tx:method的屬性: * name 是必須的,表示與事務屬性關聯的方法名(業務方法名),對切入點進行細化。通配符 (*)能夠用來指定一批關聯到相同的事務屬性的方法。 如:'get*'、'handle*'、'on*Event'等等. * propagation:不是必須的,默認值是REQUIRED表示事務傳播行爲, 包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED * isolation:不是必須的 默認值DEFAULT ,表示事務隔離級別(數據庫的隔離級別) * timeout:不是必須的 默認值-1(永不超時),表示事務超時的時間(以秒爲單位) * read-only:不是必須的 默認值false不是隻讀的表示事務是否只讀? * rollback-for: 不是必須的表示將被觸發進行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException' * no-rollback-for:不是必須的表示不被觸發進行回滾的 Exception(s),以逗號分開。 如:'com.foo.MyBusinessException,ServletException' 任何 RuntimeException 將觸發事務回滾,可是任何 checked Exception 將不觸發事務回滾 --> <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/> <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/> <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" rollback-for="Exception"/> <!-- 其餘的方法之只讀的 --> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice>