在 Spring 项目中处理事务
在 Spring 项目中,处理事务主要有两种方式:编程式事务管理和声明式事务管理,下面分别进行介绍。
1. 编程式事务管理
编程式事务管理是通过编写代码来控制事务的边界,这种方式比较灵活,但代码量较大,维护成本较高。
示例代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.sql.DataSource;
@Service
public class ProgrammaticTransactionService {
@Autowired
private DataSource dataSource;
public void performTransaction() {
// 创建事务管理器
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
// 定义事务属性
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 获取事务状态
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 执行数据库操作
// ...
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
}
}
}
2. 声明式事务管理
声明式事务管理是通过 AOP(面向切面编程)来实现的,它将事务管理代码从业务逻辑中分离出来,使得代码更加简洁和易于维护。Spring 提供了基于 XML 配置和基于注解两种方式来实现声明式事务管理。
基于注解的声明式事务管理示例:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DeclarativeTransactionService {
@Transactional
public void performTransaction() {
// 执行数据库操作
// ...
}
}
同时,需要在配置类中启用事务管理:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
事务的传播行为
事务的传播行为定义了在嵌套事务调用时,事务如何进行传播。Spring 定义了 7 种事务传播行为,下面分别进行介绍:
1. PROPAGATION_REQUIRED
(默认)
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 业务逻辑
methodB();
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
// 业务逻辑
}
在上述示例中,methodA
调用 methodB
时,如果 methodA
已经开启了一个事务,methodB
会加入到该事务中;如果 methodA
没有开启事务,则 methodA
和 methodB
会共同创建一个新的事务。
2. PROPAGATION_SUPPORTS
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 业务逻辑
methodB();
}
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
// 业务逻辑
}
在上述示例中,如果 methodA
开启了事务,methodB
会加入到该事务中;如果 methodA
没有开启事务,methodB
会以非事务方式执行。
3. PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {
// 业务逻辑
}
如果调用 methodB
时没有开启事务,会抛出 IllegalTransactionStateException
异常。
4. PROPAGATION_REQUIRES_NEW
无论当前是否存在事务,都会创建一个新的事务,并挂起当前事务(如果存在)。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 业务逻辑
methodB();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 业务逻辑
}
在上述示例中,methodB
会创建一个新的事务,并且 methodA
的事务会被挂起,直到 methodB
的事务完成。
5. PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,则挂起当前事务。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 业务逻辑
methodB();
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodB() {
// 业务逻辑
}
在上述示例中,methodB
会以非事务方式执行,并且 methodA
的事务会被挂起,直到 methodB
执行完成。
6. PROPAGATION_NEVER
以非事务方式执行操作,如果当前存在事务,则抛出异常。
@Transactional(propagation = Propagation.NEVER)
public void methodB() {
// 业务逻辑
}
如果调用 methodB
时存在事务,会抛出 IllegalTransactionStateException
异常。
7. PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新的事务。嵌套事务是外部事务的一部分,外部事务回滚时,嵌套事务也会回滚,但嵌套事务回滚不会影响外部事务。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 业务逻辑
methodB();
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
// 业务逻辑
}
在上述示例中,methodB
会在 methodA
的事务内部创建一个嵌套事务。