Spring 事務還能這樣管理?
本文轉載自微信公眾號「程序員千羽」,作者程序員千羽。轉載本文請聯系程序員千羽公眾號。
GitHub:https://github.com/nateshao/ssm/tree/master/105-spring-transaction
1.Spring事務管理概述
什么是Spring的事務管理?
在實際開發中,操作數據庫時都會涉及到事務管理問題,為此Spring提供了專門用于事務處理的API。Spring的事務管理簡化了傳統的事務管理流程,并且在一定程度上減少了開發者的工作量。
Spring事務管理的三個核心接口。
在該JAR包的org.springframework.transaction包中,有3個接口文件PlatformTransactionManager、TransactionDefinition和TransactionStatus
事務管理的核心接口
Platform TransactionManager
PlatformTransactionManager接口是Spring提供的平臺事務管理器,主要用于管理事務。該接口中提供了三個事務操作的方法,具體如下:
- TransactionStatus getTransaction(TransactionDefinition definition):用于獲取事務狀態信息
- void commit(TransactionStatus status):用于提交事務
- void rollback(TransactionStatus status):用于回滾事務
PlatformTransactionManager接口只是代表事務管理的接口,并不知道底層是如何管理事務的,具體如何管理事務則由它的實現類來完成。該接口常見的幾個實現類如下:
小提示:當底層采用不同的持久層技術時,系統只需使用不同的PlatformTransactionManager實現類即可。
TransactionDefinition
TransactionDefinition接口是事務定義(描述)的對象,該對象中定義了事務規則,并提供了獲取事務相關信息的方法,具體如下:
- String getName( ); 獲取事務對象名稱
- int getIsolationLevel( ); 獲取事務的隔離級別
- int getPropagationBehavior( ); 獲取事務的傳播行為
- int getTimeout( );獲取事務的超時時間
- boolean isReadOnly( ); 獲取事務是否只讀
上述方法中,事務的傳播行為是指在同一個方法中,不同操作前后所使用的事務。傳播行為有很多種,具體如下表所示:
在事務管理過程中,傳播行為可以控制是否需要創建事務以及如何創建事務,通常情況下,數據的查詢不會影響原數據的改變,所以不需要進行事務管理,而對于數據的插入、更新和刪除操作,必須進行事務管理。如果沒有指定事務的傳播行為,Spring默認傳播行為是REQUIRED。
TransactionStatus
TransactionStatus接口是事務的狀態,它描述了某一時間點上事務的狀態信息。該接口中包含6個方法,具體如下:
- void flush(); 刷新事務
- boolean hasSavepoint(); 獲取是否存在保存點
- boolean isCompleted(); 獲取事務是否完成
- boolean isNewTransaction(); 獲取是否為新事務
- boolean isRollbackOnly(); 獲取事務是否回滾
- void setRollbackOnly(); 設置事務回滾
聲明式事務管理最大的優點在于開發者無需通過編程的方式來管理事務,只需在配置文件中進行相關的事務規則聲明,就可以將事務應用到業務邏輯中。這使得開發人員可以更加專注于核心業務邏輯代碼的編寫,在一定程度上減少了工作量,提高了開發效率,所以在實際開發中,通常都推薦使用聲明式事務管理。
2. 聲明式事務管理
如何實現Spring的聲明式事務管理?
Spring的聲明式事務管理可以通過兩種方式來實現, **一種是基于XML的方式,另一種是基于Annotation的方式。**接下來的兩個小節中,將對這兩種聲明式事務管理方式進行詳細講解。
基于XML方式的聲明式事務
配置< tx:advice >元素的重點是配置< tx:method >子元素,上圖中使用灰色標注的幾個屬性是< tx:method >元素中的常用屬性。其屬性描述具體如下:
Account.java
- @Data
- public class Account {
- private Integer id; // 賬戶id
- private String username; // 用戶名
- private Double balance; // 賬戶余額
- }
AccountDao.java
- public interface AccountDao {
- .........
- // 轉賬
- public void transfer(String outUser,String inUser,Double money);
- }
AccountDaoImpl.java
- @Transactional(propagation = Propagation.REQUIRED,
- isolation = Isolation.DEFAULT, readOnly = false)
- @Override
- public void transfer(String outUser, String inUser, Double money) {
- // 收款時,收款用戶的余額=現有余額+所匯金額
- this.jdbcTemplate.update("update account set balance = balance +? "
- + "where username = ?",money, inUser);
- // 模擬系統運行時的突發性問題
- // int i = 1/0;
- // 匯款時,匯款用戶的余額=現有余額-所匯金額
- this.jdbcTemplate.update("update account set balance = balance-? "
- + "where username = ?",money, outUser);
- }
TransactionTest.java
- package com.nateshao.jdbc;
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- /**
- * @date Created by 邵桐杰 on 2021/10/15 22:05
- * @微信公眾號 程序員千羽
- * @個人網站 www.nateshao.cn
- * @博客 https://nateshao.gitee.io
- * @GitHub https://github.com/nateshao
- * @Gitee https://gitee.com/nateshao
- * Description:
- */
- public class TransactionTest {
- @Test
- public void xmlTest() {
- ApplicationContext applicationContext =
- new ClassPathXmlApplicationContext("applicationContext.xml");
- // 獲取AccountDao實例
- AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
- // 調用實例中的轉賬方法
- accountDao.transfer("千羽", "千尋", 100.0);
- // 輸出提示信息
- System.out.println("轉賬成功!");
- }
- }
基于Annotation方式的聲明式事務
在Spring容器中注冊事務注解驅動;
- <tx:annotation-driven transaction-manager="transactionManager"/>
在需要事務管理的類或方法上使用@Transactional注解。
如果將注解添加在Bean類上,則表示事務的設置對整個Bean類的所有方法都起作用;如果將注解添加在Bean類中的某個方法上,則表示事務的設置只對該方法有效。
使用@Transactional注解時,可以通過參數配置事務詳情:
applicationContext-annotation.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-4.3.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
- <!-- 1.配置數據源 -->
- <bean id="dataSource"
- class="org.springframework.jdbc.datasource.DriverManagerDataSource">
- <!--數據庫驅動 -->
- <property name="driverClassName" value="com.mysql.jdbc.Driver" />
- <!--連接數據庫的url -->
- <property name="url" value="jdbc:mysql://localhost/spring?useSSL=false" />
- <!--連接數據庫的用戶名 -->
- <property name="username" value="root" />
- <!--連接數據庫的密碼 -->
- <property name="password" value="123456" />
- </bean>
- <!-- 2.配置JDBC模板 -->
- <bean id="jdbcTemplate"
- class="org.springframework.jdbc.core.JdbcTemplate">
- <!-- 默認必須使用數據源 -->
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!--3.定義id為accountDao的Bean -->
- <bean id="accountDao" class="com.nateshao.jdbc.AccountDaoImpl">
- <!-- 將jdbcTemplate注入到AccountDao實例中 -->
- <property name="jdbcTemplate" ref="jdbcTemplate" />
- </bean>
- <!-- 4.事務管理器,依賴于數據源 -->
- <bean id="transactionManager" class=
- "org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 5.注冊事務管理器驅動 -->
- <tx:annotation-driven transaction-manager="transactionManager"/>
- </beans>
TransactionTest.java
- package com.nateshao.jdbc;
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- /**
- * @date Created by 邵桐杰 on 2021/10/15 22:05
- * @微信公眾號 程序員千羽
- * @個人網站 www.nateshao.cn
- * @博客 https://nateshao.gitee.io
- * @GitHub https://github.com/nateshao
- * @Gitee https://gitee.com/nateshao
- * Description:
- */
- public class TransactionTest {
- @Test
- public void annotationTest() {
- ApplicationContext applicationContext =
- new ClassPathXmlApplicationContext("applicationContext-annotation.xml");
- // 獲取AccountDao實例
- AccountDao accountDao =
- (AccountDao) applicationContext.getBean("accountDao");
- // 調用實例中的轉賬方法
- accountDao.transfer("千尋111", "千羽111", 100.0);
- // 輸出提示信息
- System.out.println("轉賬成功!");
- }
- }
總結
本章主要對Spring中的事務管理進行了詳細講解。
- 首先講解了Spring事務管理所涉及的3個核心接口,
- 然后對Spring中事務管理的兩種方式進行了介紹,
- 最后通過案例分別對基于XML方式和基于Annotation方式的聲明式事務處理的使用進行了詳細講解。
通過本章的學習,我相信大家可以對Spring的事務管理知識有一定的了解,并能夠掌握Spring聲明式事務管理的使用。