Spring事務( Transaction )
事務的概念
事務是一些sql語句的集合,作為一個整體執行,一起成功或者一起失敗。
使用事務的時機
一個操作需要多天sql語句一起完成才能成功
程序中事務在哪里說明
加在業務類的方法上面(public方法上面),表示業務方法執行時,需要事務的支持。
不同的事務管理器
不同的數據庫訪問技術,處理事務是不同的
-
使用
jdbc
訪問數據庫,事務處理public void updateAccount(){ Connection con = .....; con.setAutoCommit(false); state.insert(); state.update(); state.commit(); con.setAutoCommit(true); }
-
MyBatis執行數據庫,處理事務
public void updateAccount(){ SqlSession sqlSession = SqlSessionFactory.openSession(false); try{ sqlSession.insert(...); sqlSession.update(...); sqlSession.commit(); }catch(Exception e){ sqlSession.rollback(); } }
spring統一管理事務,把不同的數據庫訪問技術的事務處理統一起來
使用spring的事務管理器,管理不同數據庫訪問技術的事務處理。開發人員只需要掌握spring的事務處理一個方案,就可以實現使用不同數據庫訪問技術的事務管理。
盡管事務面向的是spring,有spring管理事務,做事務提交和回滾。
spring事務管理器
spring框架使用事務管理器對象,管理所有的事務。
事務管理器接口: PlatFormTransactionManager
作用 :定義了事務的操作,主要是commit() , rollback()
事務管理器有很多的實現類:一種數據庫訪問計數有一個實現類。由實現類具體完成事務的提交,回滾。
這意味着:JDBC或者MyBatis訪問數據庫有自己的事務管理實現類:DataSourceTransactionManager
hibernate框架,他的事務管理器實現類:HibernateTransactionManager
事務管理器的工作方式
spring集中統一管理事務,分配管理事務給具體的事務管理器對象。
事務提交和回滾的時機
當業務正常執行的時候,沒有異常,事務是提交的。如果業務代碼中出現了運行時異常,事務會發生回滾。
異常的分類:
- Error : 錯誤,回滾事務
- Exception:
- 運行時異常:RuntimeException和他的子類都是運行時異常,在程序執行過程中拋出的異常
- 受查異常:在編寫代碼時需要處理的異常(編譯都無法通過),會提交事務。
方法拋出運行時異常事務回滾,其他的情況都是執行事務。
spring事務管理的實現方式:AOP中的環繞通知
環繞通知:在目標方法的前后都可以增加功能,不需要修改代碼。
// spring給業務方法在執行時,增加事務的切面功能(一下為大致的實現步驟,不是真正的執行代碼)
@Around("execution(* com.wang.*.*(..))")
public Object myAround(ProceedingJoinPoint pjp){
try{
PlatformTransactionManager.beginTransaction(); // 使用spring的事務管理器,開啟事務
pjp.proceed(); // 執行目標方法
PlatformTransactionManager.commit(); // 業務方法正常執行,事務提交
}catch(Exception e){
PlatformTransactionManager.roolback(); // 業務方法非正常執行,事務回滾
}
}
事務定義接口(TransactionDefinition )
事務定義接口TransactionDefinition中定義了事務描述相關的三類常量:事務隔離級別,事務傳播行為,事務默認超時時限,及他們的操作。
給業務方法說明事務的屬性。
隔離級別
定義
控制事務之間的影響速度
具體值
DEFAULT
:采用DB默認的事務隔離級別。Mysql
的默認為REPEATABLE_READ
,Oracle
默認為READ_COMMITTED
READ_UNCOMMITTED
:讀未提交。未解決任何並發問題READ_COMMITTER
:讀已提交。解決臟讀,存在不可重復讀和幻讀REPETABLE_READ
:可重復讀。解決臟讀,不可重復讀,存在幻讀SERIALIZABLE
:串行化。不存在並發問題。
事務超時時間
以秒為單位,整數值,默認為-1
超時時間:表示一個業務方法最長的執行時間,到達時間沒有執行完畢,spring會回滾事務。
傳播行為
傳播行為有7個值
定義:業務方法在調用的時候,事務在方法之間的傳遞和使用。
使用傳播行為,表示方法有無事務。
-
PROPAGATION_REQUIRED
-
PROPAGATION_REQUIRES_NEW
-
PROPAGATION_SUPPORTS
以上三個需要掌握
-
PROPAGATION_MANDATORY
-
PROPAGATION_NESTED
-
PROPAGATION_NEVER
-
PROPAGATION_NOT_SUPPORTED
- PROPAGATION_REQUIRED:spring默認傳播行為,方法在調用的時候,如果存在事務就是用當前的事務,如果沒有事務,就新建一個事務,方法在新事務中執行。
- PROPAGATION_SUPPORTS: 方法有事務可以正常執行,沒有事務也可以正常執行。(查詢操作)
- PROPAGATION_REQUIRES_NEW:方法需要一個新事務。如果調用方法的時候,存在一個事務,則原來的事務暫停,知道新事務執行完畢。如果方法調用的時候,沒有事務,則新建一個事務,在新事務中執行代碼。
spring框架使用自己的注解@Transactional控制事務
@Transactional
注解,使用注解的屬性控制事務(隔離級別,傳播行為,超時)
其中的屬性:
propagation
:事務的傳播行為,他使用的Propagation
類的枚舉值,例如:Propagation.REQUIRED
;isolation
:表示隔離級別,使用Isolation
類的枚舉值,表示隔離級別,默認是:Ioslation.DEFAULT
;readOnly
:boolean類型的值,表示數據庫操作是不是只讀的,默認為falsetimeout
:事務超時,默認是-1,整數值,單位是秒,例如:timeout=20;rollbackFor
:表示回滾的異常類列表,他的值是一個數組,每個值是異常類型的class。rollbackForClassName
:表示回滾的異常類列表,是String類型的值noRollbackFor
:不需要回滾的異常類列表,是class類型的noRollbackForClassName
:不需要回滾的異常類列表,是String類型的值
該注解放置的位置:
- 在業務方法上面,實在public方法上面(大多數)
- 在類的上面(幾乎見不到)
注解的使用步驟
-
在spring配置文件中,聲明事務的內容;
聲明事務管理器,說明使用哪個事務管理器對象;
聲明使用注解管理事務,開啟注解驅動
-
在類的源代碼中,加入
@Transactional
事務的控制模式:
- 編程式,在代碼中編程控制事務
- 聲明式事務,不用編碼
步驟一:
<!--聲明事務管理器(連接到數據庫,做事務提交,事務回滾)-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<!--指定數據源-->
<property name="dataSource" ref="myDataSource"/>
</bean>
<!--開啟事務注解驅動-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--最后導入的包是以tx結尾-->
步驟二:
在具體的方法上加上@Transactional注解
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
timeout = 20,
rollbackFor = {NullPointerException.class}
)
@Override
public void buy(Integer goodId, Integer amount) throws Exception {
System.out.println("buy方法的執行");
Sale sale = new Sale();
sale.setGid(goodId);
sale.setNums(amount);
// 生成銷售記錄
saleDao.insertSale(sale);
// 查詢商品
Good good = goodDao.selectById(goodId);
if (good == null){
throw new Exception("商品不存在");
}else if (good.getAmount() < amount){
throw new Exception("庫存不足");
}
// 更新庫存
Good good1 = new Good();
good1.setId(goodId);
good1.setAmount(amount);
goodDao.updateGood(good1);
System.out.println("buy方法的完成");
}
rollbackFor說明
- 框架首先檢查方法拋出的異常是不是在rollbackFor數組中,如果在一定會發生回滾;
- 如果方法拋出的異常不在rollbackFor數組中,框架會繼續檢查拋出的異常是不是RuntimrException,如果是
RuntimeException
,一定會發生回滾。
使用rollbackFor可以實現發生受檢查異常時讓其發生回滾。
注解的使用特點
直接使用@Transactional
會使用默認值
- spring框架自己提供的事務控制
- 適合中小型項目,注解都放置在了源代碼中,不利於優化
- 使用方便效率高
使用Aspectj框架在spring配置文件中,聲明事務控制
使用aspectj的aop,聲明事務控制叫做聲明式事務
使用步驟
- 加入
spring-aspectj
的依賴 - 在
spring
的配置文件聲明事務屬性- 聲明事務管理器
- 聲明業務方法需要的事務屬性
- 聲明切入點表達式
步驟
基本上是模板化的方法
<!--聲明式事務-->
<!--1.聲明事務管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager2">
<property name="dataSource" ref="myDataSource"/>
</bean>
<!--2.聲明業務方法的事務屬性(隔離級別,傳播行為,超時)
id:給業務方法配置事務段代碼起個名字,唯一值
transaction-manager:事務管理器的id
-->
<tx:advice id="serviceAdvice" transaction-manager="transactionManager2">
<!--給具體的業務方法增加事務的說明-->
<tx:attributes>
<!-- 給具體的業務方法,說明他需要的事務屬性
name:業務方法名稱,配置name的值 1.業務方法的名稱(類中的某一個方法) 2.帶有部分通配符的方法名稱 3.使用*
propagation:指定傳播行為
isolation:隔離級別
read-only:是否只讀,默認為false
timeout:超時時間
rollback-for:指定回滾的異常類列表,使用的異常類的全限定名稱(多個異常時用都好分割)
-->
<tx:method name="buy"
isolation="DEFAULT"
propagation="REQUIRED"
timeout="20"
rollback-for="java.lang.NullPointerException"
/>
<!--在業務方法有命名規則的時候,可以對一些方法使用事務-->
<tx:method name="add*" propagation="REQUIRED" timeout="20" isolation="DEFAULT"/>
<tx:method name="delete*" propagation="REQUIRED" timeout="20" isolation="DEFAULT"/>
<!--以上方法以外的-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--通過上述方法的聲明,但是我們並不知道是哪個類的方法,讓上述聲明生效的方法:切入點表達式-->
<!--聲明切入點表達式:表示哪些包中的哪些類的方法參與事務-->
<aop:config>
<!--聲明切入點表達式
expression:切入點表達式,表示哪些類中的哪些方法要參與事務
id:切入點表達式的名稱,唯一值
-->
<aop:pointcut id="servicePointCut" expression="execution(* *..service..*.*(..))"/>
<!-- 關聯切入點表達式和事務的通知-->
<aop:advisor advice-ref="serviceAdvice" pointcut-ref="servicePointCut"/>
</aop:config>
優缺點
-
缺點:理解難,配置復雜
-
優點:代碼和事務分開。控制事務源代碼不用修改。
能快速的了解和掌握項目的全部事務。適合大型項目。