事務(wù)回顧
事務(wù)指的是邏輯上的一組操作航徙,這組操作要么全部成功湿酸,要么全部失敗接剩。事務(wù)操作能夠保證數(shù)據(jù)操作的安全性枣氧。
以一個(gè)簡單的銀行轉(zhuǎn)賬案例說明,張三和李四賬戶都有兩千元截粗,現(xiàn)在張三要給李四轉(zhuǎn)賬1000元信姓,那么需要兩步操作,第一修改張三賬戶扣除1000元绸罗,第二修改李四賬戶增加1000元意推。這個(gè)轉(zhuǎn)賬操作不應(yīng)該出現(xiàn)張三轉(zhuǎn)賬時(shí)由于某種原因錢轉(zhuǎn)出去了但李四沒收到。所以對于這樣一組操作我們應(yīng)該用事務(wù)來進(jìn)行管理珊蟀。那么一旦這組操作加入到了事務(wù)管理之中左痢,它們就必須一起成功或者一起失敗。
事務(wù)的特性(ACID特性)
- 原子性(Atomicity)
原子性是指事務(wù)是一個(gè)不可分割的工作單位系洛,事務(wù)中的操作要么都發(fā)生要么都不發(fā)生 - 一致性(Consistency)
一致性指事務(wù)前后數(shù)據(jù)的完整性必須保持一致 - 隔離性(Isolation)
事務(wù)的隔離性是指多個(gè)用戶并發(fā)訪問數(shù)據(jù)庫時(shí),一個(gè)用戶的事務(wù)不能被其他用戶的事務(wù)所干擾略步,多個(gè)并發(fā)事務(wù)之間數(shù)據(jù)要相互隔離 - 持久性(Durability)
持久性是指一個(gè)事務(wù)一旦被提交描扯,它對數(shù)據(jù)庫中數(shù)據(jù)的改變就是永久性的,即使數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對其有任何影響
Spring事務(wù)接口
Spring事務(wù)管理高層抽象主要包括3個(gè)接口:PlatformTransactionManager
平臺事務(wù)管理器趟薄,TransactionDefinition
事務(wù)定義信息(隔離绽诚、傳播、超時(shí)杭煎、只讀)恩够,TransactionStatus
事務(wù)具體運(yùn)行狀態(tài)。
Spring在進(jìn)行事務(wù)管理的時(shí)候首先會根據(jù)事務(wù)定義信息羡铲,由事務(wù)管理器真正進(jìn)行事務(wù)管理操作(事務(wù)提交蜂桶、回滾等),在進(jìn)行事務(wù)管理過程中事務(wù)會產(chǎn)生一些相應(yīng)的狀態(tài)也切,這些狀態(tài)就保存在TransactionStatus
中扑媚。
PlatformTransactionManager接口
Spring為不同的持久化框架提供了不同PlatformTransactionManager
接口實(shí)現(xiàn)腰湾,通常我們都是使用前兩種。
TransactionDefinition定義事務(wù)隔離級別
如果不考慮隔離性疆股,會引發(fā)安全問題如下:臟讀费坊、不可重復(fù)讀、幻讀旬痹,隔離級別就是用來解決這幾種讀的問題的附井。
正常情況下數(shù)據(jù)庫為我們提供了四種隔離級別,而default是spring提供的選擇項(xiàng)两残。
TransactionDefinition定義事務(wù)傳播行為
事務(wù)傳播行為主要解決業(yè)務(wù)層方法之間的相互調(diào)用而產(chǎn)生的事務(wù)應(yīng)該如何傳遞的問題永毅。比如在a方法中調(diào)用了b方法
對于第一種類型來說如果a里面有事務(wù),b方法就使用a的事務(wù)磕昼,如果a沒有事務(wù)卷雕,b方法就新建事務(wù),并把a(bǔ)內(nèi)容包裹進(jìn)來票从,意思是a和b這兩個(gè)操作是在同一個(gè)事務(wù)之間的漫雕。類型2/3表示a沒有事務(wù),b方法就不使用事務(wù)/拋出異常峰鄙。
后三種類型作為一類浸间,表示a和b這兩個(gè)操作沒有在同一個(gè)事務(wù)中。
最后一種類型是嵌套事務(wù)吟榴,當(dāng)a執(zhí)行完成以后可以設(shè)置一個(gè)保存點(diǎn)魁蒜,如果b發(fā)生異常之后可以回滾到保存點(diǎn)位置,或者最初始狀態(tài)吩翻。
TransactionDefinition接口方法
Timeout:
事務(wù)超時(shí)兜看,就是指一個(gè)事務(wù)所允許執(zhí)行的最長時(shí)間,如果超過該時(shí)間限制事務(wù)還沒有完成狭瞎,則自動回滾事務(wù)细移。
ReadOnly:
默認(rèn)為false,也就是讀寫事務(wù)熊锭,如果設(shè)置只讀事務(wù)則不允許對數(shù)據(jù)進(jìn)行增刪改弧轧,只讀事務(wù)用于特定情景下的優(yōu)化。
TransactionStatus接口
Spring事務(wù)管理
Spring支持兩種方式事務(wù)管理方式碗殷,編程式事務(wù)管理和聲明式事務(wù)管理精绎。
編程式事務(wù)管理通過TransactionTemplate手動管理事務(wù),在實(shí)際應(yīng)用中很少使用锌妻。聲明式事務(wù)管理是通過AOP實(shí)現(xiàn)的代乃,開發(fā)中推薦使用(代碼侵入性小)。
編程式事務(wù)管理
這種方式不推薦實(shí)際使用仿粹,僅提供實(shí)現(xiàn)思路供參考襟己。
1.配置事務(wù)管理器TransactionManager
引谜,并在事務(wù)管理器中配置連接池dataSource
屬性。
2.配置事務(wù)管理的模版TransactionTemplate
擎浴,并在事務(wù)管理模版中配置事務(wù)管理器屬性员咽。
3.在業(yè)務(wù)類中注入模版類,并調(diào)用其方法進(jìn)行事務(wù)控制贮预。
聲明式事務(wù)管理
聲明式事務(wù)管理共有3種實(shí)現(xiàn)方式贝室,分別是基于TransactionProxyFactoryBean
的方式、基于AspectJ
的XML方式以及基于注解的方式仿吞。
由于第一種方式配置較為繁瑣(需要為每個(gè)進(jìn)行事務(wù)管理的類配置一個(gè)這樣的Bean進(jìn)行增強(qiáng))滑频,通常實(shí)際開發(fā)不采用,這里我們只介紹后兩種方式唤冈,也是實(shí)際開發(fā)常用的兩種方式峡迷。
基于AspectJ的XML方式
基于這種方式我們只需要進(jìn)行相關(guān)的配置即可,業(yè)務(wù)代碼不需要做任何處理你虹,注意在配置文件的頭部需要添加aop和tx的命名空間绘搞。
<!-- 配置連接池,這里以druid為例傅物,連接池相關(guān)參數(shù)省略 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://xxx:3306/xxx"></property>
<property name="username" value="root"></property>
<property name="password" value="root123"></property>
</bean>
<!-- 配置事務(wù)管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事務(wù)的通知:(事務(wù)的增強(qiáng)) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- propagation:事務(wù)傳播行為夯辖,isolation:事務(wù)隔離級別,read-only:只讀 -->
<!-- rollback-for:發(fā)生哪些異扯危回滾蒿褂,no-rollback-for:發(fā)生哪些異常不回滾,timeout:超時(shí)時(shí)間 -->
<tx:method name="delet*" propagation="REQUIRED" read-only="false" />
<tx:method name="save*" propagation="REQUIRED" read-only="false" />
<tx:method name="updat*" propagation="REQUIRED" read-only="false" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入點(diǎn) -->
<aop:pointcut expression="execution(* com.rxy.*.service.*Service.*(..))"" id="pointcut1" />
<!-- 配置切面 -->
<aop:advisor pointcut-ref="pointcut1" advice-ref="txAdvice" />
</aop:config>
基于注解的方式
- 添加配置
<!-- 配置事務(wù)管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 開啟注解事務(wù) -->
<tx:annotation-driven transaction-manager="transactionManager" />
- 使用注解@Transactional
@Transactional
可以作用于接口卒暂、接口方法啄栓、類以及類方法上。當(dāng)作用于類上時(shí)也祠,該類的所有 public 方法將都具有該類型的事務(wù)屬性谴供,同時(shí),我們也可以在方法級別使用該標(biāo)注來覆蓋類級別的定義齿坷。
我們更推薦將注解使用在類以及類方法上,而不是接口数焊。并且@Transactional
注解應(yīng)該只被應(yīng)用到 public 方法上永淌。
//如果注解不定義任何屬性,會使用其默認(rèn)值佩耳,屬性的含義參考xml方式的配置說明
@Transactional(propagation=Propagation.NOT_SUPPORTED)
public class AccountServiceImpl {
//方法注解會覆蓋類注解上的相同屬性
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_UNCOMMITTED)
public void transfer(final String out, final String in, final Double money){
//業(yè)務(wù)邏輯遂蛀,調(diào)用dao方法
}
}