Spring常见的事务失效场景及解决方案

 更新时间:2024年11月21日 10:22:55   作者:小沈同学呀  
Spring 事务管理是企业级应用开发中不可或缺的一部分,它可以帮助我们确保数据的一致性和完整性,然而,在实际开发中,由于各种原因,事务可能会失效,本文将详细介绍 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事务失效场景及解决的资料请关注脚本之家其它相关文章!

相关文章

  • 关于SpringBoot的自动装配原理详解

    关于SpringBoot的自动装配原理详解

    这篇文章主要介绍了关于SpringBoot的自动装配原理详解,Spring Boot自动装配原理是指Spring Boot在启动时自动扫描项目中的依赖关系,根据依赖关系自动配置相应的Bean,从而简化了Spring应用的配置过程,需要的朋友可以参考下
    2023-07-07
  • Java系统升级与迁移的完整指南

    Java系统升级与迁移的完整指南

    在Java生态中,系统升级和迁移是开发者必须面对的“成人礼”,从JAR地狱到模块化战争,从Java 8到Java 17的版本跳跃,每一次升级都伴随着技术债的清算、架构的重构和性能的飞跃,所以本文给大家介绍了Java系统升级与迁移的完整指南,需要的朋友可以参考下
    2025-08-08
  • 关于QueryWrapper,实现MybatisPlus多表关联查询方式

    关于QueryWrapper,实现MybatisPlus多表关联查询方式

    这篇文章主要介绍了关于QueryWrapper,实现MybatisPlus多表关联查询方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教。
    2022-01-01
  • Java中的WeakHashMap详解

    Java中的WeakHashMap详解

    这篇文章主要介绍了Java中的WeakHashMap详解,WeakHashMap可能平时使用的频率并不高,但是你可能听过WeakHashMap会进行自动回收吧,下面就对其原理进行分析,需要的朋友可以参考下
    2023-09-09
  • mybatis如何使用Criteria的and和or进行联合查询

    mybatis如何使用Criteria的and和or进行联合查询

    这篇文章主要介绍了mybatis如何使用Criteria的and和or进行联合查询,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • 推荐几本学习java的书籍

    推荐几本学习java的书籍

    本文给大家推荐了几本学习Java的书籍,非常适合Java的初学者,有需要的朋友可以看看
    2014-10-10
  • java控制台实现学生信息管理系统(集合版)

    java控制台实现学生信息管理系统(集合版)

    这篇文章主要为大家详细介绍了java控制台实现学生信息管理系统的集合版,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • java日志门面之JCL和SLF4J详解

    java日志门面之JCL和SLF4J详解

    这篇文章主要给大家介绍了关于java日志门面之JCL和SLF4J的相关资料,在系统开发过程中日志框架的选择与更换是一大挑战,日志门面的概念,如JCL和SLF4J,允许开发者面向接口编程,文中介绍的非常详细,需要的朋友可以参考下
    2024-10-10
  • 使用 Spring Boot 实现 WebSocket实时通信

    使用 Spring Boot 实现 WebSocket实时通信

    本篇文章主要介绍了使用 Spring Boot 实现 WebSocket实时通信,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Java中线程中断的几种方法小结

    Java中线程中断的几种方法小结

    在Java中,线程中断是一种协作机制,它通过设置线程的中断标志位来通知线程需要中断,本文主要介绍了Java中线程中断的几种方法小结,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12

最新评论