一、事務概念
事務是一組由一個或多個操作組成的不可分割的工作單元,這些操作要麼全部成功,要麼全部失敗。在關係型數據庫中,事務是指一組SQL語句組成的操作序列,具有四個特性:原子性、一致性、隔離性和持久性。
二、Spring 事務處理
Spring 通過TransactionManager來統一管理事務,支持聲明式事務和編程式事務兩種方式。其中,聲明式事務可以通過AOP實現,而編程式事務可以通過編寫代碼來實現。
三、Spring 事務傳播行為
Spring 定義了七種事務傳播行為,用於配置事務的傳播屬性,確保多個事務之間的正確性和一致性。
1、PROPAGATION_REQUIRED(默認值)
如果當前存在事務,則加入該事務;如果不存在事務,則創建一個新事務。
@Transactional(propagation = Propagation.REQUIRED) public void method(){ // 事務代碼 }
2、PROPAGATION_SUPPORTS
如果當前存在事務,則加入該事務;如果不存在事務,則以非事務的方式繼續執行。
@Transactional(propagation = Propagation.SUPPORTS) public void method(){ // 事務代碼 }
3、PROPAGATION_MANDATORY
如果當前存在事務,則加入該事務;如果不存在事務,則拋出異常。
@Transactional(propagation = Propagation.MANDATORY) public void method(){ // 事務代碼 }
4、PROPAGATION_REQUIRES_NEW
創建一個新事務,並且暫停當前事務(如果存在)。
@Transactional(propagation = Propagation.REQUIRES_NEW) public void method(){ // 事務代碼 }
5、PROPAGATION_NOT_SUPPORTED
以非事務方式執行操作,如果當前存在事務,則掛起該事務。
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void method(){ // 事務代碼 }
6、PROPAGATION_NEVER
以非事務方式執行操作,如果當前存在事務,則拋出異常。
@Transactional(propagation = Propagation.NEVER) public void method(){ // 事務代碼 }
7、PROPAGATION_NESTED
如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則相當於PROPAGATION_REQUIRED。
@Transactional(propagation = Propagation.NESTED) public void method(){ // 事務代碼 }
四、Spring 事務傳播案例
下面我們通過一個簡單的案例來說明 Spring 事務傳播的使用。
1、創建數據庫表
創建一個名為 user 的表,用於演示 Spring 事務傳播功能的使用。
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2、添加依賴
Pom.xml 文件中添加 Spring Boot 相關依賴。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
3、配置數據源
在 application.properties 文件中添加數據源相關配置。
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver
4、創建User實體類
創建 User 實體類。
public class User { private int id; private String name; private int age; // 省略 getter 和 setter 方法 }
5、添加數據訪問對象
創建 UserDAO 接口和實現類,用於操作數據庫。
public interface UserDAO { void addUser(User user); void addUserWithRequired(User user); void addUserWithRequiresNew(User user); } @Repository public class UserDAOImpl implements UserDAO { @Autowired private JdbcTemplate jdbcTemplate; @Override public void addUser(User user) { String sql = "INSERT INTO user(name, age) VALUES(?, ?)"; jdbcTemplate.update(sql, new Object[]{user.getName(), user.getAge()}); } @Override @Transactional(propagation = Propagation.REQUIRED) public void addUserWithRequired(User user) { String sql = "INSERT INTO user(name, age) VALUES(?, ?)"; jdbcTemplate.update(sql, new Object[]{user.getName(), user.getAge()}); throw new RuntimeException(); } @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void addUserWithRequiresNew(User user) { String sql = "INSERT INTO user(name, age) VALUES(?, ?)"; jdbcTemplate.update(sql, new Object[]{user.getName(), user.getAge()}); throw new RuntimeException(); } }
6、添加服務層
創建 UserService 接口和實現類,用於操作數據庫。
public interface UserService { void addUser(User user); void addUserWithRequired(User user); void addUserWithRequiresNew(User user); } @Service public class UserServiceImpl implements UserService { @Autowired private UserDAO userDAO; @Override @Transactional public void addUser(User user) { userDAO.addUser(user); throw new RuntimeException(); } @Override @Transactional public void addUserWithRequired(User user) { userDAO.addUserWithRequired(user); } @Override @Transactional public void addUserWithRequiresNew(User user) { userDAO.addUserWithRequiresNew(user); } }
7、寫測試類
創建一個測試類,測試 Spring 事務傳播的效果。
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) public class UserServiceImplTest { @Autowired private UserService userService; @Autowired private UserDAO userDAO; @Test(expected = RuntimeException.class) public void testTransactionRequired() { User user = new User(); user.setName("John"); user.setAge(20); userService.addUserWithRequired(user); } @Test(expected = RuntimeException.class) public void testTransactionRequiresNew() { User user = new User(); user.setName("John"); user.setAge(20); userService.addUserWithRequiresNew(user); } }
總結
本文詳細介紹了 Spring 事務傳播的概念、配置方式和七種傳播行為,並提供了一個簡單的案例,演示了 Spring 事務傳播機制的實際使用。掌握了事務傳播的知識,能夠在必要的時候進行正確的配置,確保多個事務之間的正確性和一致性。
原創文章,作者:AAZAW,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/372133.html