Spring 事务失效场景
- 事务配置错误
- 在接口内直接调用另一个事务管理的接口
- 在私有方法上开启事务
- 在final方法上开启事务
- Bean对象没有被事务管理
- 在新线程中调用事务接口
- 异常被捕获
...
场景1 持久层对象与事务管理器使用的数据源不一致
@Component
public class AppConfig {
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
@Bean
public DataSourceTransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
return transactionManager;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource datasource = new DriverManagerDataSource();
datasource.setUrl("jdbc:mysql://192.168.1.100:3307/tt_test");
datasource.setUsername("root");
datasource.setPassword("Aa.123456");
return datasource;
}
}
在创建 JdbcTemplate / DataSourceTransactionManager 时DataSource不是由容器注入的, 而是直接的方法调用
这会导致创建两个不同的DataSource对象, 在管理事务的时候, 会在代理对象中使用 DataSourceTransactionManager 中的DataSource创建连接并存入 ThreadLocal<DataSource, Connection> 中,JdbcTemplate 在执行sql时, 会使用自己的 DataSource 在ThreadLocal 中获取连接, 由于是不同的DataSource对象, 所以获取不到连接, 然后就会自己创建一个连接
此连接没有关闭自动提交, 于是事务失效
解决办法
-
使用 Bean 注入的方式在JdbcTemplate 和 DataSourceTransactionManager 中使用同一个DataSource
@Component public class AppConfig { @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean public DataSourceTransactionManager transactionManager(DataSource dataSource) { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } @Bean public DataSource dataSource() { DriverManagerDataSource datasource = new DriverManagerDataSource(); datasource.setUrl("jdbc:mysql://192.168.1.100:3307/tt_test"); datasource.setUsername("root"); datasource.setPassword("Aa.123456"); return datasource; } } -
使用 @Configuration 注解
此注解会创建AppConfig 代理对象,代理对象中的方法调用会先从Spring 容器中获取对应的Bean, 而不是直接的方法调用创建新的对象@Configuration //使用 public class AppConfig { @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dataSource()); } @Bean public DataSourceTransactionManager transactionManager() { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource()); return transactionManager; } @Bean public DataSource dataSource() { DriverManagerDataSource datasource = new DriverManagerDataSource(); datasource.setUrl("jdbc:mysql://192.168.1.100:3307/tt_test"); datasource.setUsername("root"); datasource.setPassword("Aa.123456"); return datasource; } }

浙公网安备 33010602011771号