管理事务的方式

  1. 编程式事务,在代码中编码
  2. 声明式事务,在配置文件中配置
    1. 基于xml的声明式事务
    2. 基于注解的声明式事务

spring 事务的隔离级别与传播级别

TransactionDefinition 接⼝中定义了五个表示隔离级别的常量

  1. TransactionDefinition.ISOLATION_DEFAULT: 使⽤后端数据库默认的隔离级别,Mysql 默认采⽤的 REPEATABLE_READ隔离级别 Oracle 默认采⽤的 READ_COMMITTED隔离级 别.
  2. TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取 尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  3. TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的 数据,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣
  4. TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同⼀字段的多次读取结果 都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有 可能发⽣。
  5. TransactionDefinition.ISOLATION_SERIALIZABLE: 最⾼的隔离级别,完全服从ACID的 隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该 级别可以防⽌脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不 会⽤到该级别。

事务中传播行为

⽀持当前事务的情况:

  1. TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加⼊该事 务;如果当前没有事务,则创建⼀个新的事务。
  2. TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加⼊该事 务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。
  3. TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加⼊该事 务;如果当前没有事务,则抛出异常。(mandatory:强制性)

不⽀持当前事务的情况:

  1. TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建⼀个新的事务,如果当 前存在事务,则把当前事务挂起。
  2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以⾮事务⽅式运⾏,如果 当前存在事务,则把当前事务挂起。
  3. TransactionDefinition.PROPAGATION_NEVER: 以⾮事务⽅式运⾏,如果当前存在事 务,则抛出异常

其他情况:
TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建⼀个事务 作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED

  1. import com.wpw.group.springstudy.sql.User;
  2. import com.wpw.group.springstudy.sql.UserMapper;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Service;
  5. import org.springframework.transaction.annotation.Isolation;
  6. import org.springframework.transaction.annotation.Propagation;
  7. import org.springframework.transaction.annotation.Transactional;
  8. @Service
  9. public class TransactionService {
  10. @Autowired
  11. private UserMapper userMapper;
  12. //由于 @Transactional 采用的是代理模式,采用this调用不会生效,所以这里通过自引用的方式来调用。
  13. @Autowired
  14. private TransactionService transactionService;
  15. /**
  16. * 由于远程调用的是 方法是读未提交的,所以会返回数据
  17. * @return
  18. */
  19. @Transactional
  20. public User readUncommitIsolation() {
  21. User user = new User();
  22. user.setName("name");
  23. user.setSex("sex");
  24. userMapper.insertSelective(user);
  25. return transactionService.getReadUncommit(user.getId());
  26. }
  27. /**
  28. * 采用的是读未提交隔离级别,调用这个方法的会读取到未提交的事务
  29. * @param id
  30. * @return
  31. */
  32. @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED)
  33. public User getReadUncommit(Long id) {
  34. return userMapper.selectByPrimaryKey(id);
  35. }
  36. /**
  37. * 远程调用的是 默认隔离级别的方法,即可重复读,因此此处会返回null
  38. * @return
  39. */
  40. @Transactional
  41. public User defaultIsolation() {
  42. User user = new User();
  43. user.setName("name");
  44. user.setSex("sex");
  45. userMapper.insertSelective(user);
  46. return transactionService.getDefault(user.getId());
  47. }
  48. /**
  49. * 未配置隔离级别,会使用默认隔离级别,即数据库默认的事务隔离级别,mysql的默认的隔离级别是 可重复读,所以调用这个方法不会返回数据
  50. * @param id
  51. * @return
  52. */
  53. @Transactional(propagation = Propagation.REQUIRES_NEW)
  54. public User getDefault(Long id) {
  55. return userMapper.selectByPrimaryKey(id);
  56. }
  57. }