事务隔离级别(isolation)
- 读未提交
- 读已提交
- 可重复读
- 可串行化
数据库和Spring指定隔离级别不同时
若数据库支持Spring事务设置的隔离级别,则以Spring设置的为准;反之,以数据库的隔离级别为准。
事务传播(propagation)
传播类型
OrderService#generateOrder
和AccountService#deductStock
REQUIRED
@Transactional public void generateOrder() { System.out.println("下单"); accountService.deductStock(); } // generateOrder方法存在事务,deductStock就加入,不存在就新建。 @Transactional(propagation = Propagation.REQUIRED) public void deductStock() { System.out.println("扣减库存"); }
SUPPORTS
@Transactional public void generateOrder() { System.out.println("下单"); accountService.deductStock(); } // generateOrder方法存在事务,deductStock就加入,不存在就以非事务方式执行,即跟随 @Transactional(propagation = Propagation.SUPPORTS) public void deductStock() { System.out.println("扣减库存"); }
MANDATORY(强制性的)
@Transactional public void generateOrder() { System.out.println("下单"); accountService.deductStock(); } // generateOrder方法存在事务,deductStock就加入,不存在则抛异常 @Transactional(propagation = Propagation.MANDATORY) public void deductStock() { System.out.println("扣减库存"); }
REQUIRES_NEW
@Transactional public void generateOrder() { System.out.println("下单"); accountService.deductStock(); } // deductStock方法总是会创建新事务,generateOrder方法存在事务时,则会将其挂起,即 // deductStock方法与generateOrder方法的事务无关,互不干扰。 @Transactional(propagation = Propagation.REQUIRES_NEW) public void deductStock() { System.out.println("扣减库存"); }
NOT_SUPPORTED
@Transactional public void generateOrder() { System.out.println("下单"); accountService.deductStock(); } // deductStock方法以非事务方式执行,generateOrder方法存在事务时,则会将其挂起。 @Transactional(propagation = Propagation.NOT_SUPPORTED) public void deductStock() { System.out.println("扣减库存"); }
NEVER
@Transactional public void generateOrder() { System.out.println("下单"); accountService.deductStock(); } // deductStock方法以非事务方式执行,generateOrder方法存在事务时,则会抛异常。 @Transactional(propagation = Propagation.NEVER) public void deductStock() { System.out.println("扣减库存"); }
NESTED
@Transactional public void generateOrder() { System.out.println("下单"); accountService.deductStock(); } // generateOrder方法存在事务时,deductStock方法则会开启子事务。若子事务的异常信息被catch了,则父事务不会进行回滚 // generateOrder方法不存在事务时,deductStock方法则会开启新事务 @Transactional(propagation = Propagation.NESTED) public void deductStock() { System.out.println("扣减库存"); }
事务失效场景
场景一: 同类中非事务方法调用事务方法
@Service public class UserService { @Autowired private UserDao userDao; // 非事务方法调用事务方法 public void transfer() { transfer(1,2); } /** * 事务不会生效 * @param fromId * @param toId */ @Transactional public void transfer(int fromId, int toId) { userDao.deductBalance(fromId); int i = 1 / 0; userDao.recharge(toId); } }
应用场景
存在3个方法,在a方法中调用了b和c方法,实现b事务失败只回滚b中的事务,c事务失败回滚整个事务。
@Service public class AService { @Autowired private BService bService; @Autowired private CService cService; @Transactional public void a() { try { bService.b(); } catch (Exception e) { System.out.println("事务失败"); } cService.c(); } } @Service public class BService { // b事务是a事务的子事务,在a事务中已经将b事务的异常捕获了,所以b事务失败只会回滚自己的事务,不影响整个事务 // 此处不可用REQUIRES_NEW传播方式,因为c事务失败后,在REQUIRES_NEW传播方式下,b事务不会跟着回滚 @Transactional(propagation = Propagation.NESTED) public void b() { // 数据库操作 } } @Service public class CService { @Transactional public void c() { // 数据库操作 } }
超时时间(timeout)
设置事务等待的超时时间。