Spring常见的事务失效场景及解决方案
作者:小沈同学呀
常见失效场景
1.方法不是 public
Spring AOP 代理默认只对 public 方法生效。如果被 @Transactional 注解的方法不是 public 的,事务将不会生效。
示例代码
@Service
public class UserService {
@Transactional
protected void updateUser(User user) {
// 更新用户信息
}
}
解决方案: 将方法改为 public。
@Service
public class UserService {
@Transactional
public void updateUser(User user) {
// 更新用户信息
}
}
2.自我调用问题
当一个类中的方法调用同一个类中的另一个 @Transactional 方法时,事务不会传播到被调用的方法。
示例代码:
@Service
public class UserService {
@Transactional
public void updateUser(User user) {
internalUpdate(user);
}
@Transactional
private void internalUpdate(User user) {
// 更新用户信息
}
}
解决方案: 使用 AopContext.currentProxy() 或者通过 @Autowired 注入当前类的代理对
@Service
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void updateUser(User user) {
userService.internalUpdate(user);
}
@Transactional
private void internalUpdate(User user) {
// 更新用户信息
}
}
3.异常被捕获
如果在事务方法中捕获了异常并且没有重新抛出,Spring 框架无法检测到异常,从而不会回滚事务。
示例代码:
@Service
public class UserService {
@Transactional
public void updateUser(User user) {
try {
// 更新用户信息
} catch (Exception e) {
// 异常被捕获,事务不会回滚
}
}
}
解决方案: 捕获异常后重新抛出,或者使用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。
@Service
public class UserService {
@Transactional
public void updateUser(User user) {
try {
// 更新用户信息
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
}
4.配置错误
事务管理器配置错误或未正确配置,例如 @EnableTransactionManagement 缺失或事务管理器 bean 名称不匹配。
示例代码:
@Configuration
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public DataSource dataSource() {
// 配置数据源
}
}
解决方案: 确保 @EnableTransactionManagement 注解存在,并且事务管理器配置正确。
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public DataSource dataSource() {
// 配置数据源
}
}
5.事务传播行为
不正确的事务传播行为设置可能导致事务不按预期工作。例如,使用 REQUIRES_NEW 传播行为时,新的事务会被创建,但原来的事务可能不会回滚。
示例代码
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser(User user) {
// 更新用户信息
}
}
解决方案: 根据业务需求选择合适的事务传播行为。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void updateUser(User user) {
// 更新用户信息
}
}
6.事务隔离级别
不合适的事务隔离级别可能导致数据一致性问题,例如脏读、不可重复读和幻读。
示例代码
@Service
public class UserService {
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void updateUser(User user) {
// 更新用户信息
}
}
解决方案: 根据业务需求选择合适的事务隔离级别。
@Service
public class UserService {
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateUser(User user) {
// 更新用户信息
}
}
7.事务超时
事务超时设置不合理,导致事务在执行过程中被自动回滚。
示例代码:
@Service
public class UserService {
@Transactional(timeout = 1) // 超时时间设置为1秒
public void updateUser(User user) {
// 更新用户信息
}
}
解决方案: 根据业务需求设置合理的事务超时时间。
@Service
public class UserService {
@Transactional(timeout = 60) // 超时时间设置为60秒
public void updateUser(User user) {
// 更新用户信息
}
}
8.只读事务
如果事务被标记为只读(readOnly=true),则不能进行任何修改操作,否则会抛出异常。
示例代码:
@Service
public class UserService {
@Transactional(readOnly = true)
public User getUserById(Long id) {
// 查询用户信息
}
}
解决方案: 确保只读事务中不进行任何修改操作。
@Service
public class UserService {
@Transactional(readOnly = false)
public void updateUser(User user) {
// 更新用户信息
}
}
9.数据库连接问题
数据库连接池配置不当或数据库连接断开,导致事务无法正常提交或回滚。
示例代码:
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("password");
return new HikariDataSource(config);
}
}
解决方案: 确保数据库连接池配置正确,并且数据库连接稳定。
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(10); // 设置最大连接数
return new HikariDataSource(config);
}
}
10.事务管理器不匹配
使用了错误的事务管理器,例如在使用 JPA 时配置了 JDBC 事务管理器,或者在使用 MyBatis 时配置了 Hibernate 事务管理器。
示例代码:
@Configuration
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
}
解决方案: 根据使用的持久层框架选择合适的事务管理器。
@Configuration
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
总结
Spring 事务管理虽然强大,但在实际开发中需要注意许多细节。本文列举了十种常见的事务失效情况,并提供了相应的解决方案和示例代码。希望这些内容能帮助开发者更好地理解和使用 Spring 事务管理,确保数据的一致性和完整性。
以上就是Spring常见的事务失效场景及解决方案的详细内容,更多关于Spring事务失效场景及解决的资料请关注脚本之家其它相关文章!
