本地事务

事务四大特性

原子性:事务中所有的操作要么全部执行成功,要么全部不执行
一致性:事务执行前后数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的
隔离性:多个事务并发访问时,事务之间是相互隔离的
持久性:事务执行成功后对数据库所作的操作将持久化到数据库中

事务四大隔离等级

ReadUnCommit:多个不同的事务操作同一条数据,事务A读取到了事务B未提交的数据(脏读)

在这里插入图片描述

ReadCommit:多个不同的事务操作同一条数据,可以有效的解决脏读的问题,但是不能保证同一事务中的相同查询操作的结果一致(不可重复读)

在这里插入图片描述

ReadRepeatable:多个不同的事务操作同一条数据,可以有效的解决不可重复读的问题,但是可能会出现幻读的问题(幻读)
Serializable:该数据库隔离等级最高,多个不同的事务操作同一条数据,可以有效的解决脏读、不可重复度读、幻读的问题,但是性能是个问题

@Transactional(Spring声明式事务注解)

基于AOP面向切面,它将具体业务与事务处理部分解耦,所以在实际开发中声明式事务用的比较多
声明式事务也有两种实现方式,一是基于TX和AOP的xml配置文件方式,二种就是基于@Transactional注解(作用在接口、类、类方法)
作用在类上时表示该类所有的public方法都配置相同的事务属性信息,若其方法也配置了@Transactional,则方法的事务会覆盖类的事务配置信息
不推荐作用在接口上,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效
  • 传播行为(7)
    PROPAGATION_required(默认):当前存在事务则加入该事务,否则创建一个新的事务
    PROPAGATION_nested:当前存在事务则创建一个事务作为当前事务的嵌套事务来运行
    否则等价于默认传播行为
    PROPAGATION_supports:当前存在事务则加入该事,否则以非事务继续运行
    PROPAGATION_mandatory:当前存在事务则加入该事务,否则抛出异常
    PROPAGATION_requires_new:当前存在事务则挂起,然后创建一个新的事务
    PROPAGATION_not_supported:当前存在事务则挂起,然后以非事务继续运行
    PROPAGATION_never:当前存在事务则抛出异常,然后以非事务方式运行
  • 隔离等级(4)
    READ_UNCOMMITTED:允许另外一个事务可以看到这个事务未提交的数据
    READ_COMMITTED:保证一个事物提交后才能被另外一个事务读取
    REPEATABLE_READ:防止脏读,不可重复读
    SERIALIZABLE:串化读
  • 失效场景
@GetMapping("testTransactional")
@Transactional
void testTransactional() {
    
    
    // 修改买家等级
    buyerService.update(new UpdateWrapper<BuyerEntity>().set("grade", 0).eq("account", "31011225"));
    // 修改卖家等级
    sellerService.update(new UpdateWrapper<SellerEntity>().set("grade", 0).eq("account_", "31011225"));
}
// 错误信息
### SQL: UPDATE seller  SET grade=?      WHERE (account_ = ?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'account_' in 'where clause'

在这里插入图片描述
结论:@Transactional修饰的方法为非public时,则事务不会生效

@GetMapping("testTransactional")
@Transactional
public void testTransactional() {
    
    
   // 修改买家等级
   buyerService.update(new UpdateWrapper<BuyerEntity>().set("grade", 0).eq("account", "31011225"));
   // 修改卖家等级
   try {
    
    
       sellerService.update(new UpdateWrapper<SellerEntity>().set("grade", 0).eq("account_", "31011225"));
   } catch (Exception e) {
    
    
       LoggerUtil.error(e.getMessage());
   }
}
// 错误信息
### SQL: UPDATE seller  SET grade=?      WHERE (account_ = ?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'account_' in 'where clause'

在这里插入图片描述
结论:如果异常被捕获了,则事务不会生效

@GetMapping("testTransactional")
public void testTransactional() {
    
    
   	buyerService.updateA();
}
//
@Service
public class BuyerServiceImpl extends ServiceImpl<BuyerMapper, BuyerEntity> implements BuyerService {
    
    
    @Resource
    private SellerService sellerService;

    @Override
    public void updateA() {
    
    
        // 修改买家等级
        this.update(new UpdateWrapper<BuyerEntity>().set("grade", 0).eq("account", "31011225"));
        updateB();
    }

    @Override
    @Transactional
    public void updateB() {
    
    
        // 修改卖家等级
        sellerService.update(new UpdateWrapper<SellerEntity>().set("grade", 0).eq("account_", "31011225"));
    }
}
// 错误信息
### SQL: UPDATE seller  SET grade=?      WHERE (account_ = ?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'account_' in 'where clause'

在这里插入图片描述
结论:updateB被@Transactional修饰,则事务只对updateB生效,对于updateA则事务不会生效;如果updateA被@Transactional修饰,即使updateB没有,因为updateB是在updateA中调用,所有这两个方法都在同一个事物中

猜你喜欢

转载自blog.csdn.net/qq_30818545/article/details/121198745