一、事務概念
事務是一組由一個或多個操作組成的不可分割的工作單元,這些操作要麼全部成功,要麼全部失敗。在關係型數據庫中,事務是指一組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-hant/n/372133.html
微信掃一掃
支付寶掃一掃