在日常開發中,有時候業務需求的原因,需要在Service層中本類的test()調用本類test2()方法,這時候test2()如果執行中發生異常,test()不會回滾,演示代碼如下:
@ComponentScan("com.zlm")
@EnableAspectJAutoProxy
@EnableTransactionManagement
@Configuration
public class AppConfig {
@Bean
public JdbcTemplate jdbcTemplate(){
return new JdbcTemplate(dataSource());
}
@Bean
public PlatformTransactionManager transactionManager(){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
return transactionManager;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&serverTimezone=Asia/Shanghai");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
}
@Component
public class UserService{
@Autowired
private OrderService orderService;
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional(rollbackFor = Exception.class)
public void test(){
jdbcTemplate.execute("insert into user values(12,'zs')");
test2();
}
//Propagation.NEVER表示調用該方法的調用方如果有事務就拋出異常
@Transactional(propagation = Propagation.NEVER,rollbackFor = Exception.class)
public void test2(){
System.out.println("test2()");;
}
}
public class Test {
public static void main(String[] args) {
String str = "UserService";
System.out.println(Introspector.decapitalize(str));
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();
}
}
我們會發現上面代碼執行完后代碼并沒有報錯,數據庫中數據也插入了,并且也執行了test2().
分析問題原因:
spring事務控制是通過AOP來控制的,AOP又是使用動態代理來實現的,在main()中獲取到的userService對象是代理對象,在執行test()是會先進入代理類的test()方法,在代理類test()中會對@Transactional做處理,然后才會執行真正的userService.test(),這時候執行到test2()時調用方已經不是代理類而是userService本身,所以不會對test2()上的注解做處理.
通過上面分析可以得出,只要讓調用test2()時的調用對象是代理對象即可,解決方法:
將test()和test2()分成兩個類,調用test2()是注入test2()所在類的代理對象調用.
在UserService中注入自己,調用test2()是使用注入的對象調用.