事务四大特性:
ACID:原子性,一致性,隔离性,持久性。
隔离性:
读未提交:一个事务还没提交时,他做的变更就能被其他事务看到。
读提交:一个事务提交之后,他做的变更才会被别的事务看到。
可重复读:一个事务在执行的过程中总是和他启动时所看到的数据一致。
串行化:隔离级别最高,对于同一行记录,读会加读锁,写会加写锁。当发生读写冲突时后访问的事务必须等待前一个事务执行完,才能继续执行。
事务隔离的实现(MVCC):
在mysql中,每条记录在更新的时候都会生成一条回滚操作,记录上的最新值可以根据回滚操作得到之前的版本,所以每行数据都有多个版本,而每个事务都有一个事务id,transcation id,每次事务更新数据的时候,都会生成新的数据版本,并把transcation id赋给这个数据版本的事务id,记为row trx_id。同时旧的数据版本也要保留,在新的数据版本中能够有信息可以直接拿到它。也就是说数据表中的一行数据,有多个版本(row),每个版本都有自己的row trx_id。
在事务的启动瞬间,innodb为每个事务构造一个数组,存放当前正活跃的所有事务id,活跃指启动但还没提交。
数组里面事务id最小值记为低水位,当前系统里面已经创建过的事务id的最大值加1记为高水位。这个视图数组和高水位组成当前事务的一致性视图(read-view)。数据版本的可见性规则就是基于数据的row trx_id和一致性视图的对比结果得到的。
一个数据版本,对于一个事务视图来说,除了自己的更新总是可见外,有三种情况:
1.版本未提交,不可见。
2.版本已提交,但是是在视图创建后提交的,不可见。
3.版本已提交,而且是在视图创建前提交的,可见。
更新数据的时候都是先读后写的。而这个读只能读当前值,称为当前读(current read)
select 语句如果加锁,也是当前读(加上 lock in share mode 或 for update)
可重复读的核心就是一致性读(consistent read),而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。
长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。