事务就是要保证一组数据库操作,要么全部成功,要么全部失败。
ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)
原子性(Atomicity)
也就是我们刚才说的不可再分,也就意味着我们对数 据库的一系列的操作,要么都是成功,要么都是失败,不可能出现部分成功或者部分失 败的情况。以转账的场景为例,一个账户的余额减少,对应一个账户的增加,这两个一 定是同时成功或者同时失败的。
一致性(consistent)
指的是数据库的完整性约束没有被破坏,事务执行的 前后都是合法的数据状态。比如主键必须是唯一的,字段长度符合要求。
隔离性(Isolation)
在数据库里面会有很多的 事务同时去操作我们的同一张表或者同一行数据,必然会产生一些并发或者干扰的操作, 那么我们对隔离性的定义,就是这些很多个的事务,对表或者行的并发操作,应该是透 明的,互相不干扰的。通过这种方式,我们最终也是保证业务数据的一致性。
持久性(Durable)
我们对数据库的任意 的操作,增删改,只要事务提交成功,那么结果就是永久性的,不可能因为我们系统宕 机或者重启了数据库的服务器,它又恢复到原来的状态了。这个就是事务的持久性。
持久性是通过 redo log 和 double write 双写缓冲来实现的,我们操作数据的时候,会先写到内存的 buffer pool 里面,同时记录 redo log,如果在刷盘之前出现异常,在 重启后就可以读取 redo log 的内容,写入到磁盘,保证数据的持久性。
手动开启事务也有几种方式?
一种是用 begin;一种是用 start transaction。
结束也有两种方式,第一种就是提交一个事务, commit;还有一种就是 rollback,回滚的时候,事务也会结束。还有一种情况,客户端 的连接断开的时候,事务也会结束。
事务隔离级别
- 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
- 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
- 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
- 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了。因此,V2、V3 也都是 2。
若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是 2。
若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。
若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。
事务并带来的问题?
读取到其他事务未提交的数据的情况,我们把它叫做脏读。
一个事务读取到了其他事务已提交的数据导致前后两次读取数据不一致的情 况,我们把它叫做不可重复读。
一个事务前后两次读取数据数据不一致,是由于其他事务插入数据造成的,这种情 况我们把它叫做幻读。
不可重复读是修改或者删除,幻读是插入。
MVVC
MVCC (Multiversion Concurrency Control) 中文全程叫多版本并发控制,是现代数据库(包括 MySQL、Oracle、PostgreSQL 等)引擎实现中常用的处理读写冲突的手段,目的在于提高数据库高并发场景下的吞吐性能。
- 插入数据(insert):记录的版本号即当前事务的版本号
insert into testmvcc values(1,"test");
假设事务id为1,那么插入后的数据行如下:
id | name | create version | delete version |
---|---|---|---|
1 | test | 1 |
- 在更新操作的时候,采用的是先标记旧的那行记录为已删除,并且删除版本号是事务版本号,然后插入一行新的记录的方式。
比如,针对上面那行记录,事务Id为2 要把name字段更新
update table set name= 'new_value' where id=1;
id | name | create version | delete version |
---|---|---|---|
1 | test | 1 | 2 |
1 | new_value | 2 |
- 删除操作的时候,就把事务版本号作为删除版本号。比如
delete from table where id=1;
id | name | create version | delete version |
---|---|---|---|
1 | test | 2 | 3 |
查询操作:
从上面的描述可以看到,在查询时要符合以下两个条件的记录才能被事务查询出来:
删除版本号未指定或者大于当前事务版本号,即查询事务开启后确保读取的行未被删除。(即上述事务id为2的事务查询时,依然能读取到事务id为3所删除的数据行)
创建版 本号 小于或者等于 当前事务版本号 ,就是说记录创建是在当前事务中(等于的情况)或者在当前事务启动之前的其他事物进行的insert。
补充:
MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read).
Read uncimmitted由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC.
原因是MVCC的创建版本和删除版本只要在事务提交后才会产生。
串行化由于是会对所涉及到的表加锁,并非行锁,自然也就不存在行的版本控制问题。
通过以上总结,可知,MVCC主要作用于事务性的,有行锁控制的数据库模型。