在軟件開發領域中,全有或全無的操做被稱爲事務。
java
事務容許你將幾個操做組合成一個要麼所有發生要麼所有不發生的工做單元。
web
事務的4個特性ACID:
spring
原子性(Atomic):事務是由一個或多個活動所組成的一個工做單元。數據庫
原子性確保事務中的全部操做所有發生或所有不發生。全部活動成功事務才成功,任意一個活動失敗了事務也失敗並回滾。
express
一致性(Consistent):一旦事務完成(無論成功仍是失敗),系統必須確保它所建模的業務處於一致的狀態。後端
隔離性(Isolated):事務容許多個用戶對相同的數據進行操做,每一個用戶的操做不會與其餘用戶糾纏在一塊兒。併發
事務應該被彼此隔離,避免發生同步讀寫相同數據的事情(隔離性每每涉及到鎖定數據庫的行或表)。
框架
持久性(Durable):一旦事務完成,事務的結果應該持久化,這樣就能從任何的系統崩潰中恢復過來。分佈式
這通常涉及將結果存儲到數據庫或其餘形式的持久化存儲中。
性能
若是應用程序只使用一種持久化資源,Spring可使用持久化機制自己所提供的事務性支持,包括了JDBC、Hibernate以及Java持久化API(Java Persistent API,JPA)。
可是若是應用程序的事務跨多個資源,那麼Spring會使用第三方的JTA實現來支持分佈式事務。
Spring支持編碼式事務和聲明式事務,編碼式事務容許用戶在代碼中精肯定義事務的邊界,而聲明式事務(基於AOP)有助於用於將操做與事務規則進行解耦。
Spring並不直接管理事務,而是提供了多種事務管理器,它們將事務管理的職責委託給JTA(Java Transaction API)或其餘持久化機制所提供的平臺相關的事務實現。
Spring幾種常見的事務管理器:
事務管理器 | 使用場景 |
jdbc.datasource.DataSourceTransactionManager | 用於Spring對JDBC抽象的支持,也能夠用於使用Mybatis進行持久化的場景 |
org.hibernate3.HibernateTransactionManager |
用於Hibernate3進行持久化 |
orm.jpa.JpaTransactionManager | 用於java持久化API(JPA)進行持久化 |
transaction.jta.JtaTransactionManager |
須要分佈式事務或者沒有其餘的事務管理器知足需求 |
Spring對聲明式事務的支持是經過使用Spring AOP框架實現的。這是很天然的一件事,由於事務是在應用程序主要功能之上的系統服務。能夠將Spring事務想象成方法」包裝「上事務邊界的切面。
事務屬性包含了5個方面:傳播行爲、隔離級別、是否只讀、事務超時、回讀規則。
傳播行爲
傳播行爲定義了客戶端與被調用方法之間的事務邊界。Spring定義了7種不一樣的傳播行爲,都在org.springframework.TransactionDefinition接口中以常量的方式進行了定義。
傳播行爲 | 含義 |
PROPAGATION_MANDATORY | 表示該方法必須在事務中運行,若是當前事務不存在,則會拋出一個異常 |
PROPAGATION_NESTED | 表示若是當前已經存在一個事務,那麼該方法將會在嵌套事務中運行。嵌套的事務能夠獨立於當前事務進行單獨地提交或回滾。若是當前事務不存在,那麼其行爲與PROPAGATION_REQUIRED同樣。(注意,各廠商對這種傳播行爲的支持是有所差別的。) |
PROPAGATION_NEVER | 表示當前方法不該該運行在事務上下文中,若是當前正有一個事務在運行,則會拋出異常。 |
PROPAGATION_NOT_SUPPORTED | 表示該方法不該該運行在事務中。若是存在當前事務,在該方法運行期間,當前事務將會被掛起,若是使用JTATransactionManager的話,則要訪問TransactionManager。 |
PROPAGATION_REQUIRED | 表示當前方法必須運行在事務中。若是當前事務存在,方法將會在該事務中運行,不然,會啓動一個新的事務。 |
PROPAGATION_REQUIRES_NEW | 表示當前方法必須運行在它本身的事務中。一個新的事務將會被啓動。若是存在當前事務,在該方法執行期間,當前事務會被掛起,若是使用JTATransactionManager的話,則要訪問TransactionManager。 |
PROPAGATION_SUPPORTS | 表示當前方法不須要事務上下文,可是若是存在當前事務的話,那麼該方法會在這個事務中運行。 |
隔離級別
隔離級別定義了一個事務可能受其餘併發事務影響的程度。多個事務併發運行可能致使的問題:髒讀、不可重複讀、幻讀。
隔離級別 | 含義 |
ISOLATION_DEFAULT | 使用後端數據庫默認的隔離級別 |
ISOLATION_READ_UNCOMMITTED | 容許讀取還沒有提交的數據變動。可能會致使髒讀、幻讀或不可重複讀 |
ISOLATION_READ_COMMITED | 容許讀取併發事務已經提交的數據。能夠組織髒讀,可是幻讀或不可重複仍有可能發生 |
ISOLATION_REPEATABLE_READ | 對同一字段的屢次讀取結果是一致的,除非數據是被本事務本身所修改。能夠組織髒讀和不可重複讀,但幻讀仍有可能發生 |
ISOLATION_SERIALIZABLE | 徹底服從ACID的隔離級別,確保組織髒讀、不可重複讀以及幻讀。這是最慢的事務隔離級別。由於它一般是經過徹底鎖定事務相關的數據庫表來實現的。 |
注意:並非全部的數據源都支持所列的隔離級別。
只讀
經過將事務設置爲只讀,你能夠給數據庫一個機會,讓它應用它認爲合適的優化措施。
事務超時
爲了使應用程序很好地運行,事務不能運行太長時間。能夠在特定的秒數後自動回滾,而不是等待其結束。
回滾規則
這些規則定義了哪些異常會致使事務回滾而哪些不會。默認狀況下,事務只有在遇到運行期異常時纔會回滾,而在遇到檢查型異常時不會回滾。
當利用<tx:advice>聲明事務的時候,還須要一個事務管理器transactionManager。
<tx:advice>只是定義AOP通知,用於把事務邊界通知給方法,可是這只是事務通知,而不是完整的事務性切面。咱們須要定義一個通知器(advisor),才能構成完整的事務性切面,
<!-- 對dataSource 數據源進行事務管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> <!-- 事務通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 對insert,update,delete 開頭的方法進行事務管理,只要有異常就回滾 --> <tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> <tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> <!-- select,count開頭的方法,開啓只讀,提升數據庫訪問性能 --> <tx:method name="select*" read-only="true"/> <tx:method name="count*" read-only="true"/> <!-- 對其餘方法 使用默認的事務管理 --> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 事務 aop 配置 --> <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* com.eliteams.quick4j.web.service..*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/> </aop:config>
在Spring xml中配置<tx:annotation-driven />,能夠經過其transactionmanager屬性來指定特定的事務管理器。
<tx:annotation-driven>元素告訴Spring檢查上下文中全部的Bean並查找使用@Transactional註解的Bean,而無論這個註解是用在類級別上仍是方法級別上。對於每個使用@Transactional註解的Bean,<tx:annotation-driven>會自動爲它添加事務通知。