事务隔离级别(isolation)

  • 读未提交
  • 读已提交
  • 可重复读
  • 可串行化

数据库和Spring指定隔离级别不同时

若数据库支持Spring事务设置的隔离级别,则以Spring设置的为准;反之,以数据库的隔离级别为准。

事务传播(propagation)

传播类型

OrderService#generateOrderAccountService#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)

    设置事务等待的超时时间。