美文网首页
Mysql-事务

Mysql-事务

作者: 麦大大吃不胖 | 来源:发表于2020-12-08 14:06 被阅读0次

    by shihang.mai

    1. Mysql事务

    简称:ACID

    特性 解析
    原子性 要么全部成功,要么全部失败
    一致性 事务开启前和事务结束后,并不会存在中间状态。其他3个特性保证了这个特性。
    隔离性 各个事务之间不相互影响。默认隔离级别可重复读
    持久性 所以数据的修改都必须持久化到磁盘

    隔离级别(并发事务会带来脏读、不可重复读、幻读,所以有隔离级别)

    隔离级别 解析 会导致
    读未提交 会话A->update data,not commit,会话B->select data = 能查到会话A未提交的数据。出现脏读 脏读
    读已提交 会话A->update data,not commit,会话B->不能查到会话A未提交的数据,解决了脏读。会话A->commit,会话B->查到了会话A更新的数据,但是会话B还在自己的事务内,前后查到的结果不一致。出现了不可重复读。 不可重复读
    可重复读 会话A->update data,not commit,会话B->不能查到会话A未提交的数据,解决了脏读。会话A->commit,会话B->不能查到了会话A更新的数据,会话B还在自己的事务内,前后查到的结果一致,解决了不可重复读。会话A插入一条id=5的数据,commimt,会话B也插入一条id=5的数据,发现会话B主键和重复,这就出现了幻读。 幻读
    序列化执行(串行执行) 全部做串行化操作 没异常

    隔离级别的实现是用锁实现的

    • 读未提交级别,任何操作都不加锁
    • 读已提交,基于MVCC,对于快照读不加锁,对于当前读,保证读到的记录加锁
    • 可重复读,也基于MVCC,对于快照读不加锁,对于当前读,会使用next-key lock保证读到的记录和间隙加锁
    • 序列化执行,直接都是当前读

    2. spring事务-事务的传播机制

    @Transactional(propagation = Propagation.REQUIRED)
    

    简单的理解就是多个事务方法相互调用时,事务如何在这些方法间传播。

    Spring中事务的默认实现使用的是AOP,也就是代理的方式,如果大家在使用代码测试时,同一个Service类中的方法相互调用需要使用注入的对象来调用,不要直接使用this.方法名来调用,this.方法名调用是对象内部方法调用,不会通过Spring代理,也就是事务不会起作用

    为什么不起作用,详情这个博客写得很清楚了

    事务传播
    事务传播类型 含义
    REQUIRED(默认) 如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
    SUPPORTS 当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
    MANDATORY 当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常
    REQUIRES_NEW 创建一个新事务,如果存在当前事务,则挂起该事务
    NOT_SUPPORTED 始终以非事务方式执行,如果当前存在事务,则挂起当前事务
    NEVER 不使用事务,如果当前事务存在,则抛出异常
    NESTED 如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样

    Spring7个传播事务,最特殊的是NESTED,这里有必要解析一下

    • 当外有有事务时
      嵌套事务中执行。意思就是,内层报错,不影响外层;外层报错,会影响内层
    • 当外层没事务时
      自己开一个新事务执行

    3. Spring事务-五个隔离级别

    @Transactional(isolation = Isolation.DEFAULT)
    
    隔离级别 含义
    DEFAULT 使用数据库自身的隔离级别
    READ_UNCOMMITTED 读未提交
    READ_COMMITTED 读已提交
    REPEATABLE_READ 可重复读
    SERIALIZABLE 串行化

    在开启事务时,用Isolation指定.当设置了spring的事务隔离级别,那么就按spring的事务隔离级别

    原因:spring开启事务时,拿到的当前连接,会对当前会话设置事务隔离级别

    //测试代码
    @Component
    public class Test {
    
      @Autowired
      JdbcTemplate jdbcTemplate;
    
      @Transactional
      public void test() {
    
          jdbcTemplate.execute("insert into sc(id,score) values (13,50),(14,60)");
    
          try {
              System.in.read();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
    
      @Transactional(isolation=Isolation.READ_UNCOMMITTED)
      public void sle(){
          List<Map<String, Object>> maps = jdbcTemplate.queryForList("SELECT * FROM sc");
          System.out.println(maps);
      }
    }
    

    相关文章

      网友评论

          本文标题:Mysql-事务

          本文链接:https://www.haomeiwen.com/subject/ukjziktx.html