概念
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: 2T4 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语句的开销。
- 从程序开发的角度,能明确地知道每个语句是否处于事务中。