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