MySQL-事务

212 阅读3分钟

概念

ACID

运行良好的事务处理系统,必须具备ACID特征。

  • 原子性(atomicity)
    • 整个事务的所有操作,要么全部提交成功,要么全部失败回滚。
    • 对于一个事务来说,不能只执行其中一部分操作。
  • 一致性(consistency)
    • 数据库总是从一个一致性的状态转换到另外一个一致性的状态。
  • 隔离性(isolation)
  • 持久性(durability)

脏读(dirty read)

  • 事务可以读取未提交的数据,称为脏读。

  • 场景

    时刻 事务A 事务B
    T1 begin; begin;
    T2 update t set v = 2 where v = 1;
    T3 select v from t;
    result: v: 2
    T4 commit; commit;
    • 事务A还没有提交,事务B在T3时刻查询v的时候,得到了事务A在T2时刻修改的值。

幻读(phantom read)

  • 当事务A在读取某个范围的记录时,事务B又在该范围内插入了新的记录,事务A再次读取该范围的记录,会产生幻行。
  • 场景
    时刻 事务A 事务B
    T1 begin; begin;
    T2 select * from t where v = 5;
    result: (1,5), (2,5)
    T3 insert into t values(3,5)
    T4 select * from t where v = 5;
    result: (1,5), (2,5), (3,5)
    T5 commit;
    • 在T2时刻,事务A查询到的记录有(1,5),(2,5)。
    • 在T3时刻,事务B插入新的行(3,5)。
    • 在T4时刻,事务A查询到的记录有(1,5),(2,5),(3, 5),比T1时刻查询的结果多了一行。

隔离级别

当数据库上有多个事务同时执行的时候,就有可能出现脏读、不可重复读、幻读的问题,为了解决这些问题,就有了隔离级别的概念。

读未提交(read uncommitted)

  • 事务还没提交时,它做的变更对其他事务也是可见的。
  • 从性能上来说,read uncommitted不会其他的级别好太多,但却缺乏其他级别的好处,没有非常必要的理由,不建议在实际应用中使用。

读提交(read committed)

  • 事务提交后,它做的变更才对其他事务可见。
  • 这个级别有时候也叫做不可重复读。
    • 因为两次执行同样的查询,可能会得到不一样的结果。

可重复读(repeatable read)

  • 事务执行过程中看到的数据,总是跟它启动时看到的数据是一致的。
  • 在可重复读隔离级别下,未提交的变更对其他事务也是不可见的。
  • InnoDB存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。
  • MySQL默认的事务级别。

串行化(serializable)

  • 每一行数据都加锁:读加读锁,写加写锁。
  • 可能会导致大量的超时和锁竞争的问题。
  • 实际应用中也很少用到这个隔离级别。

事务的启动方式

set autocommit=1

  • 执行单语句,会自动提交。
  • 当启动事务时(begin或start transaction),执行commit或rollback提交。

set autocommit=0

  • 会话将始终打开一个事务,直到执行commit/rollback或者断开连接。
  • 意味着select语句也会开启事务,并且不会自动提交。
  • 在每个事务启动时不需要主动执行begin,可减少语句的交互次数。

建议使用set autocommit=1。

  • 从开销的角度,执行commit work and chain,代表提交事务并自动启动下一个事务,这样也能省去再次执行begin语句的开销。
  • 从程序开发的角度,能明确地知道每个语句是否处于事务中。

参考

《高性能MySQL》第3版

极客时间《MySQL实战45讲》