场景三:
@Slf4j @Service public class HelloServiceImpl implements HelloService { @Autowired private ApplicationContext applicationContext; @Autowired private JdbcTemplate jdbcTemplate; @Transactional @Override public void enter(Integer age) { System.out.println("enter的线程:" + Thread.currentThread().getName()); String name = "fsx-" + age; String sql = "insert into user (name,age) values ('" + name + "'," + age + ")"; jdbcTemplate.update(sql); // 进来后开始吃饭(但因为吃饭比较耗时 所以放到Async异步线程里去做) applicationContext.getBean(HelloService.class).eat(age); applicationContext.getBean(HelloService.class).play(age); } @Transactional // 因为吃饭也需要原子 所以也加上事务惊醒控制 @Async @Override public void eat(Integer age) { System.out.println("eat的线程:" + Thread.currentThread().getName()); String name = "eat-" + age; String sql = "insert into eat (eat_name) values ('" + name + "')"; jdbcTemplate.update(sql); throw new RuntimeException("eat抛出运行异常"); } @Transactional @Async @Override public void play(Integer age) { System.out.println("play的线程:" + Thread.currentThread().getName()); String name = "play-" + age; String sql = "insert into play (play_name) values ('" + name + "')"; jdbcTemplate.update(sql); throw new RuntimeException("play抛出运行异常"); } }
请注意示例区别:enter方法并没有主动throw抛出异常。
现象:user表插入成功。eat和play表均插入无效(被回滚)
结论:同上
场景四:
此场是我模拟的最后一个场景:异步线程里继续调用异步线程,并且加上事务。
@Slf4j @Service public class HelloServiceImpl implements HelloService { @Autowired private ApplicationContext applicationContext; @Autowired private JdbcTemplate jdbcTemplate; @Transactional @Override public void enter(Integer age) { System.out.println("enter的线程:" + Thread.currentThread().getName()); String name = "fsx-" + age; String sql = "insert into user (name,age) values ('" + name + "'," + age + ")"; jdbcTemplate.update(sql); // 进来后开始吃饭(但因为吃饭比较耗时 所以放到Async异步线程里去做) applicationContext.getBean(HelloService.class).eat(age); } @Transactional // 因为吃饭也需要原子 所以也加上事务惊醒控制 @Async @Override public void eat(Integer age) { System.out.println("eat的线程:" + Thread.currentThread().getName()); String name = "eat-" + age; String sql = "insert into eat (eat_name) values ('" + name + "')"; jdbcTemplate.update(sql); applicationContext.getBean(HelloService.class).play(age); throw new RuntimeException("eat抛出运行异常"); } @Transactional @Async @Override public void play(Integer age) { System.out.println("play的线程:" + Thread.currentThread().getName()); String name = "play-" + age; String sql = "insert into play (play_name) values ('" + name + "')"; jdbcTemplate.update(sql); } }
请注意此示例区别:enter里没主动抛出异常。enter异步调用eat,eat再异步调用play,并且play里没有抛出异常
现象:user插入成功。eat插入无效(被回滚),play插入成功
结论:不同线程之间的事务完全隔离,异步线程内仍是可以调用异步~
总结
本文没有新的内容,源于跟一个小伙伴讨论这块时,自己也有些打鼓的地方,因此就写了本文做一个记录,还好所有结论和我"预估"的保持一致。
本文主要是把异步@Async和事务@Transactional结合使用的一个场景来进行分析,因为开发中也比较常见,因此希望把这两块内容集合使用做些示例,希望可以做到心中有数,这样使用起来才会更加的胸有成竹嘛~