一、什么是事务?ACID?
简单来说,事务就是保证我们对数据库的一组操作,要么全部成功,要么全部失败。
1.原子性:一个事务内的操作不可再分,要么全部成功,要么全部失败。
2.一致性:事务完成后,所有的数据都保持一致。
3.隔离性:由引擎层提供,保证事务不受并发影响下独立运行。
4.持久性:事务一旦提交或回滚,都是持久化的。
二、隔离性
名称 | 问题 |
脏读 | 一个事务读取到另一个事务还没提交的数据 |
不可重复读 | 一个事务先后读取两次同一条数据,但两次读取到的值不同 |
幻读 | 一个事务按照条件查询某一条数据时没有查询到,但在插入数据的时候发现这条数据又存在了 |
隔离等级 | 含义 |
读未提交 | 一个事务还没提交时,他做的变更其他事务就可以看到 |
读已提交 | 一个事务提交后,他做的变更才可以被其他事务看到 |
可重复读 | 一个事务执行过程看到的数据,总是和事务刚开始时看到的数据是一致的 |
串行化 | 对同一行数据,写会加写锁,读会加读锁。当出现锁冲突时,后来的事务要先等前面的事务执行完成 |
mysql原生的myisam引擎不支持事务,现在mysql默认使用innodb引擎,而innodb提供的事务隔离级别默认是RR(可重复读)。
举个例子:
- 在读未提交情况下:V1、V2、V3都是2,因为在事务A查询之前,事务B已经修改了数据。
- 在读已提交情况下:V1为1,V2、V3为2,只有B提交了事务,A事务才能看到B修改的值。
- 在可重复读情况下:事务A在执行的过程中看到的视图是一致的,所以V1、V2为1,V3为2。
- 在串行化情况下:V1在查询时上了读锁,此时B不可以写,B会在修改的时候发生阻塞,等事务A查询完毕后再进行修改,所以V1、V2为1,V3为2。
三、事务隔离的实现(MVCC)
在mysql更新数据时,都会记录一条回滚操作,这样通过修改后的值也可以通过回滚操作,恢复到修改之前的值。
假设一个值从4->3->2->1,如下图,回滚日志中就会有多条日志记录。
此时,如果有多个不同的事务查询这条数据库记录的话,会生成多个视图,在视图A、B、C里面,每个视图中的数据都不一样,也就是说,同一条记录,在数据库中有多个版本,这就是mysql的多版本并发控制(MVCC)。
四、避免长事务
长事务意味着系统里面可能存在很老的视图,由于长事务可能随时访问数据库中的任意一个数据,所以在这个事务提交之前,数据库中他可能用到的回滚日志都需要保留,这就会占用大量空间。长事务除了占用空间,还会占用锁资源,也可能拖垮整个库。