事務是保證業務操作完整性的一種資料庫機制,具有原子性、一致性、隔離性和持久性(ACID)的特點。 在Java中,可以通過JDBC和MyBatis來控制事務,底層都是通過Connection對象完成的。 Spring使用AOP的方式進行事務開發,通過將事務的額外功能封裝在DataSourceTrans... ...
學習視頻:【孫哥說Spring5:從設計模式到基本應用到應用級底層分析,一次深入淺出的Spring全探索。學不會Spring?只因你未遇見孫哥】
第三章、Spring的事務處理
1.什麼是事務?
事務是保證業務操作完整性的一種資料庫機制
事務的4特點:ACID
- A 原子性
- C 一致性
- I 隔離性
- D 持久性
2.如何控制事務
JDBC:
Connection.setAutoCommit(false)
Connection.commit();
Connection.rollback();
Mybatis:
Mybatis自動開啟事務
SqlSession(底層還是Connection).commit();
sqlSession(底層還是Connection).rollback();
結論:控制事務的底層 都是Connection對象完成的
3.Spring控制事務的開發
Spring是通過AOP的方式進行事務開發
-
原始對象
public class XXXUserServiceImpl{ 1.原始對象 ---> 原始方法 --->核心功能(業務處理+DAO調用) 2.DAO作為Service的成員變數,依賴註入的方式進行賦值 }
-
額外功能
下麵的額外功能封裝在org.springframework.jdbc.datasource.**DataSourceTransactionManager 應用的過程需要註入DataSource** 1.MethodInterceptor public Object invoke(MethodInvocation invocation){ try{ Connection.setAutoCommit(false); Object ret = invocation.proceed(); Connection.commit(); return ret; }catch(Exception e){ Connection.rollback(); } } 2. @Aspect @Around
-
切入點
@**Transactional** 事務的額外功能能加入給那些業務方法 1. 類上:類中所有的方法都會加入事務 2. 方法上:這個方法加入事務
-
組裝切麵
- 切入點
- 額外功能
<tx:annotation-driven transaction-manager=””/>
4.Spring控制事務的編碼
- 搭建開發環境(jar)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.14.RELEASE</version>
</dependency>
- 編碼
<!-- 1. 原始對象-->
<bean id="userService" class="com.baizhi.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!-- 2. 額外功能-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3.切入點
@Transactional
public class UserServiceImpl implements UserService {
private UserDao userDao;
<!--
4.組裝
選擇結尾是/tx的driven
-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
-
細節
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" proxy-target-class="true"/>
進行動態代理底層實現的切換 proxy-target-class
預設false:JDK true: Cglib
第四章、Spring中的事務屬性(Transaction Attribute)
1.什麼是事務屬性
屬性:描述物體特征的一系列值
性別 身高 體重…
所謂的事務屬性指的是描述事務特征的一系列值
- 隔離屬性
- 傳播屬性
- 只讀屬性
- 超時屬性
- 異常屬性
2.如何添加事務屬性
@Transactional(isolation(隔離屬性)=,propagation(傳播屬性)=,readOnly(只讀屬性)=,timeout(超時屬性)=,rollbackFor=,noRollbackFor=);
3.事務屬性詳解
1.隔離屬性(ISOLATION)
-
隔離屬性的概念
概念:他描述了事務解決併發問題的特征
-
什麼是併發
指的是多個事務(用戶)在同一時間,訪問操作了相同的數據
重點 同一時間:微小的時間內 0.0000幾秒 微小前、後
-
併發會產生那些問題
- 臟讀
- 不可重覆讀
- 幻影讀
-
併發問題如何解決
通過隔離屬性解決,隔離屬性設置不同的值,解決併發處理過程中的問題。
-
-
事務併發產生的問題
-
臟讀
指的是一個事務/用戶讀取了另外一個事務/用戶中沒有提交的數據。會在本事務中產生不一致的問題
解決方案:@Transactional(isolation=Isolation.READ.COMMITTED)
本質:只讀取已提交的數據
-
不可重覆讀
一個事務中,多次讀取相同的數據,但是讀取結果不一樣,會在本事務中產生數據不一致的問題
註意:1.不是臟讀 2.在一個事務中
解決方案:@Transactional(isolation=Isolation.REPEATABLE_READ)
本質:對應資料庫底層的行鎖(第一個人在讀取數據時,其他人都得等第一個人處理完)
-
幻影讀
一個事務中,多次對整表進行查詢統計,但是結果不一樣,會在本事務中產生數據不一致的問題。
解決方案:@Transactional(isolation=Isolation.SERIALIZABLE)
本質對應資料庫底層的表鎖
-
總結
併發安全:SERIALIZABLE>REPEATABLE_READ>READ.COMMITTED
運行效率:READ.COMMITTED>REPEATABLE_READ>SERIALIZABLE
-
-
資料庫對於隔離屬性的支持
隔離屬性的值 MySQL Oracle Isolation.READ.COMMITTED ✔️ ✔️ Isolation.REPEATABLE_READ ✔️ ❌ Isolation.SERIALIZABLE ✔️ ✔️ Oracle不支持REPETABLE_READ值 採用的是多版本比對的方式 解決不可重覆讀的問題
-
預設隔離屬性
ISOLATION_DEFAULT:會調用不同資料庫所設置的預設隔離屬性
例如:如果使用MYSQL 預設隔離屬性:REPEATABLE_READ,Oracle:READ_COMMITTED
- 查看資料庫預設隔離屬性
-
MySQL
8.0版本以前:select @@tx_isolation 8.0版本之後:select @@transaction_isolatio
-
- 查看資料庫預設隔離屬性
-
隔離屬性在實戰中的建議
推薦使用Spring指定的ISOLATION——DEFALUT
- MySQL repeatbale_read
- Oracle READ_COMMITED
未來中的實戰中,併發訪問情況 很低(前提就是海量用戶)
如果真遇到併發問題,可以使用樂觀鎖
Hibernate(JPA) Version
MyBatis 通過攔截器自定義開發
2.傳播屬性(PROPAGATION)
-
傳播屬性的概念
概念:他描述了事務解決嵌套問題的特征
什麼叫做事物的嵌套:他指的是一個大的事務中,包含若幹個小的事務
問題:大事務中融入了很多小的事務,他們彼此影響,最終導致外部大的事務,喪失了事務的原子性
-
傳播屬性的值及其用法
不管屬性是什麼,其中心思想是保證同一時間只會有一個事務的存在
傳播屬性的值 外部不存在事務 外部存在事務 用法 備註 REQUIRED 開啟新的事務 融合到外部事務中 @Transactional(propagation=Propagation.REQUIRED 主要應用於增刪改方法 SUPPORTS 不開啟新的事務 融合到外部事務中 @Transactional(propagation=Propagation.SUPPORTS 一般應用查詢方法中 REQUIRES_NEW 開啟新的事務 掛起外部事務,創建新的事務 @Transactional(propagation=Propagation.REQUIRES_NEW 日誌記錄方法中 NOT_SUPPORTED 不開啟新的事務 掛起外部事務 @Transactional(propagation=Propagation.NOT_SUPPORTED 極其不常用 NEVER 不開啟新的事務 拋出異常 @Transactional(propagation=Propagation.NEVER 極其不常用 MANDATORY 拋出異常 融合到外部事務中 @Transactional(propagation=Propagation.MANDATORY 極其不常用
融合指的是:放棄自己的事務,以外部的事務為準
-
預設的傳播屬性
REQUIRED是傳播屬性的預設值
-
推薦傳播屬性的使用方式
增刪改 方法:直接使用預設值REQUIRED
查詢 操作:顯示指定傳播屬性的值SUPPORTS
3.只讀屬性(readOnly)
針對於只進行查詢操作的業務方法,可以加入只讀屬性,提供運行效率
預設值:false
4.超時屬性(timeout)
指定了事務等待的最長時間
-
為什麼事務要進行等待呢?
因為在當前事務訪問數據時,有可能訪問的數據是被別的事務進行加鎖的處理,那麼此時本事務就必須進行等待
-
等待時間:秒
-
如何應用 @Transactional(timeout=2)
-
超時屬性的預設值:-1
最終由對應的資料庫來指定預設值,一般使用預設值
5.異常屬性
Spring事務處理過程中
預設 對於RuntimeException及其子類 採用的是回滾的策略
預設 對於Exception及其子類 採用的是提交的策略
想要改變預設的策略,可以設置兩個屬性
- rollbackFor(回滾) ={java.lang.Exception,xxx,……};
- noRollbackFor(不回滾)=
@Transactional(rollbackFor = {Exception.class},noRollbackFor = {RuntimeException.class})
建議:實戰中使用RuntimeException及其子類 使用事務異常屬性的預設值,實際開發很少改變策略
4.事務屬性常見配置總結
- 隔離屬性 預設值
- 傳播屬性 Required(預設值)增刪改 Supports 查詢操作
- 只讀屬性 readOnly false 增刪改 查詢用true
- 超時屬性 預設值:-1
- 異常屬性 預設值
後續實戰當中的建議:增刪改操作 @Transactional
而對於查詢操作 @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
5.基於標簽的事務配置方式(事務開發的第二種形式)
- 基於註解 @Transaction的事務配置回顧
<!-- 1. 原始對象-->
<bean id="userService" class="com.baizhi.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!-- 2. 額外功能-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3.切入點
@Transactional
public class UserServiceImpl implements UserService {
private UserDao userDao;
<!--
4.組裝
選擇結尾是/tx的driven
-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
- 基於標簽的事務配置
<!-- 1. 原始對象-->
<bean id="userService" class="com.baizhi.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!-- 2. 額外功能-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 第三步 事務屬性 -->
<tx:advice id="txAdvice" transacation-manager="dataSourceTransactionManager">
<tx:attributes>
<tx:method name="register" isolation="DEFAULT" propagation=""/>
<tx:method name="login"...../>
</tx:attributes>
</tx:advice>
<!-- 第四步 指定切入點-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.baizhi.service.UserServiceImpl.register(..))"/>
<aop:advisor advice-ref="" pointcut-ref="">
</aop:config>
-
基於標簽的事務配置在實戰中的應用方式
<!-- 1. 原始對象--> <bean id="userService" class="com.baizhi.service.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> <!-- 2. 額外功能--> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> **編程的時候 service 負責進行增刪改操作的方法 都以modify開頭 查詢操作 命名無所謂 用*號代替 可以將特殊事務的事務放在前面** <tx:advice id="txAdvice" transacation-manager="dataSourceTransactionManager"> <tx:attributes> <tx:method name="register" /> <tx:method name="modify*"/> <tx:method name="*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice> <!-- 第四步 指定切入點--> 使用包切入點,應用的過程中 service放置到service包中 <aop:config> <aop:pointcut id="pc" expression="execution(* com.baizhi.service..*.*(..))"/> <aop:advisor advice-ref="" pointcut-ref=""> </aop:config>
作者:揚眉劍出鞘
出處: https://www.cnblogs.com/eyewink/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。