事务具有四大特性:原子性,一致性,隔离性,持久性。
原子性是说一组操作在执行的时候是一个不可分割的整体,要么都执行,要么都不执行。
一致性不太好理解,网上的解释也五花八门,官方的解释也云里雾里。维基百科说:事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束[3]。
隔离性:事务在执行的过程中和别的事务是隔离的,一个事务的执行不能影响到另个一个事务的执行。
持久性:事务提交后,数据应该永久的被保存在数据库中。(无论海枯与石烂?)
数据库有四个隔离级别
读未提交,这个相当于没有隔离,我还没有提交就被人家看到了。这就是脏读。
读已提交,这样就不会出现脏读了,只有我提交后,别人才能看到。但是会出现不可重复读。
不可重复读是说我在事务开始的时候读取到了一个值,我还在操作的时候,有人修改了这个值并提交了,当我再次读取这个值的时候就跟我事务开始的时候读取到的不一致了。
可重复度,听这名字就解决了不可重复读。当隔离级别是可重复读时,在我事务开始的时候读到的一个值,无论别的事务如何折腾,我看到的都是最开始的值。
这个级别下还会出现幻读,幻读是不可重复的一种特殊场景,就是说在事务中两个完全相同的查询,得出了不一样的结果集,就好像出现了幻影。例如我的事务开始的时候根据where name = '张三' 条件查询了一组数据,查出了3条。这时有别的事务插入了一条数据,name也是张三,这个时候我在执行where name = '张三' 查询,就查出了4条数据。
串行化,串行化是最严格的隔离级别,当不同事务对同一组数据操作时,只能等一个事务提交,另一个事务才能操作。例如上面的例子,当一个事务查询where name = '张三'后,这个范围会被锁定,别的事务就无法在插入 name = '张三' 的数据。
多版本并发控制(MVCC)
多版本并发控制(MVCC)是数据库在并发下做事务隔离,提高数据库读写性能的一种手段。
每个事务都有一个全局唯一id,每行数据都有一个隐藏字段记录了操作这条数据的事务id, 当一条事务操作一条数据的时候,就要生成一个新的版本,新的版本里记录了操作这条数据的事务id,也记录了上一个版本的指针,用来回滚。这是数据的版本链,就是undolog。
每个事务读取数据的时候都会生成一个视图,生成视图的时机和隔离级别有关系,在读提交级别下,开始执行查询语句的时候才生成视图,可重复度级别下,在事务一开始就会生成视图。
这个视图不是真实存在的,其实是一个数据结构包括了那一刻的活跃事务id和最小活跃ID和下一个要分配的事务id。
当一个事务读一条数据的时候,就会根据数据行的事务id判断这个条数据是否可见。判断规则是小于最大事务的id,且不在活跃事务列表。因为大于最大事务id的记录是视图生成后产生的,不可见。在活跃事务列表内,说明创建视图的时候,事务还还没提交,所以不可见。小于最大事务id且不在活跃事务列表内,说明这条数据在生成视图的时候,已经提交,所以可见。
