Spring 框架基礎(05):事務管理機制,和實現方式
- 2019 年 12 月 10 日
- 筆記
一、Spring事務管理
1、基礎描述
Spring事務管理的本質就是封裝了資料庫對事務支援的操作,使用JDBC的事務管理機制,就是利用java.sql.Connection對象完成對事務的提交和回滾。
Connection conn = DriverManager.getConnection(); try { // 自動提交設置為false conn.setAutoCommit(false); // 執行增刪改查操作 // 當操作成功後手動提交 conn.commit(); } catch (Exception e) { // 出現異常,回滾所有操作 conn.rollback(); e.printStackTrace(); } finally { conn.colse(); } 2、事務常見概念
- 事務描述
事務是指作為單個邏輯工作單元執行的一系列操作(SQL語句)。這些操作要麼全部成功,要麼全部不成功。
- 特性:ACID
原子性(Atomicity):事務中的多個操作要麼都成功要麼都失敗 一致性(consistency):事務的執行的前後數據的完整性保持一致 隔離性(isolation):事務執行的過程中,不應該受到其他事務的干擾 持久性(durability):事務一旦結束,數據就持久到資料庫
- 隔離問題
臟讀:一個事務讀到另一個事務沒有提交的數據
不可重複讀:一個事務前後多次讀取相同數據,數據內容不一致,update場景問題
虛讀(幻讀):一個事務前後多次讀取,數據總量不一致,insert場景問題
- 隔離級別
read uncommitted:
事務可以讀取另一個未提交事務的數據。
read committed:
事務要等另一個事務提交後才能讀取數據,解決臟讀。
repeatable read:
在開始讀取數據時,事務開啟,不再允許修改操作,解決:臟讀、不可重複讀。
serializable:
最高事務隔離級別,事務串列化順序執行,解決臟讀、不可重複讀、幻讀。但是效率低下,耗資料庫性能。
3、事務管理API描述
PlatformTransactionManager
平台事務管理器,Spring管理事務,必須使用事務管理器進行事務配置時,核心方法:獲取事務,提交事務,回滾事務。
TransactionDefinition
該對象封裝事務詳情(事務定義、事務屬性),例如:隔離級別、是否只讀、超時時間 等。
TransactionStatus
用於記錄當前事務運行狀態。例如:是否有保存點,事務是否完成。Spring底層根據狀態進行相應操作。
4、事務案例SQL語句
CREATE TABLE user_account( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), money INT ) ENGINE=InnoDB DEFAULT CHARSET=utf8;; INSERT INTO user_account(username,money) VALUES('jack','5000'); INSERT INTO user_account(username,money) VALUES('tom','5000'); SELECT * FROM user_account ; 二、編程式事務管理
1、核心配置文件
<!-- 配置事物管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 創建事物模板 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="txManager" /> </bean> <!-- 配置轉賬介面 --> <bean id="userAccountService" class="com.spring.mvc.service.impl.UserAccountServiceImpl"> <property name="jdbcTemplate" ref="jdbcTemplate" /> <property name="transactionTemplate" ref="transactionTemplate" /> </bean>
2、演示案例
@Service public class UserAccountServiceImpl extends JdbcDaoSupport implements UserAccountService { // 注入事物模板 private TransactionTemplate transactionTemplate ; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void remittance(String remitTer, String receiver, int money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { public void doInTransactionWithoutResult(TransactionStatus arg0) { outMoney(remitTer,money); // System.out.println(1/0); innerMoney(receiver,money); } }); } private void outMoney (String remitTer, int money){ String outSql = "update user_account set money = money - ? where username = ?"; this.getJdbcTemplate().update(outSql, money ,remitTer); } private void innerMoney (String receiver, int money){ String inSql = "update user_account set money = money + ? where username = ?"; this.getJdbcTemplate().update(inSql, money,receiver); } } 三、事務代理工廠
1、核心配置
<!-- 配置轉賬介面 --> <bean id="userAccountService01" class="com.spring.mvc.service.impl.UserAccountServiceImpl01"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> <!-- 配置事務代理工廠 --> <bean id="proxyAccountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="proxyInterfaces" value="com.spring.mvc.service.UserAccountService01" /> <property name="target" ref="userAccountService01" /> <property name="transactionManager" ref="txManager" /> <property name="transactionAttributes"> <props> <!-- 默認傳播行為、隔離級別 --> <prop key="remittance">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> <!-- 異常仍然提交事務 <prop key="remittance">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.Exception</prop> --> </props> </property> </bean>
配置說明:
proxyInterfaces代理介面target代理目標類transactionManager事務管理器transactionAttributes事務屬性(事務詳情)prop.key指定方法使用當前事務配置
事務行為:
PROPAGATION傳播行為ISOLATION隔離級別readOnly是否只讀-Exception異常回滾+Exception異常提交
2、演示案例
@Service public class UserAccountServiceImpl01 extends JdbcDaoSupport implements UserAccountService01 { @Override public void remittance(String remitTer, String receiver, int money) { outMoney(remitTer,money); System.out.println(1/0); innerMoney(receiver,money); } private void outMoney (String remitTer, int money){ String outSql = "update user_account set money = money - ? where username = ?"; this.getJdbcTemplate().update(outSql, money ,remitTer); } private void innerMoney (String receiver, int money){ String inSql = "update user_account set money = money + ? where username = ?"; this.getJdbcTemplate().update(inSql, money,receiver); } } 3、測試程式碼
public class Tx_Test_02 { @Test public void test1 (){ String xmlPath = "spring-jdbc-tx-02.xml"; ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath); UserAccountService01 accountService = (UserAccountService01) context.getBean("proxyAccountService"); accountService.remittance("jack","tom",1000); } } 四、XML配置事務
首先配置事務管理器,然後配置事務屬性,最後基於AOP編程配置事務切入點。
1、核心配置
<!-- 配置事物管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置轉賬介面 --> <bean id="userAccountService01" class="com.spring.mvc.service.impl.UserAccountServiceImpl01"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> <!-- 配置事物詳情 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="remittance" propagation="REQUIRED" isolation="DEFAULT"/> </tx:attributes> </tx:advice> <!-- 事務切入點,基於AOP編程 --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.spring.mvc.service.UserAccountService01.*(..))"/> </aop:config>
五、基於事務註解
配置事務管理器,並啟動事務註解的支援,在目標類或目標方法添加@Transactional核心註解即可。
1、核心配置
<!-- 配置事物管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 支援事務註解 --> <tx:annotation-driven transaction-manager="txManager" />
2、註解用法
註解寫在介面方法上,或者介面實現的方法上效果一樣。
public interface UserAccountService02 { @Transactional(rollbackFor = Exception.class) void remittance(String remitTer, String receiver, int money) ; } 六、源程式碼地址
GitHub·地址 https://github.com/cicadasmile/spring-mvc-parent GitEE·地址 https://gitee.com/cicadasmile/spring-mvc-parent

