之前在深入了解数据库理论的时候,了解到事物的不同隔离级别可能存在的问题。为了更好的理解所以在MySQL数据库中测试复现这些问题。关于脏读和不可重复读在相应的隔离级别下都很容易的复现了。但是对于幻读,我发现在可重复读的隔离级别下没有出现,当时想到难道是MySQL对幻读做了什么处理?
测试:
创建一张测试用的表dept:
CREATE TABLE `dept` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 insert into dept(name) values("后勤部") 事物 1事物 2begin begin
select * from dept
- insert into dept(name) values("研发部")
- commit
select * from dept
commit
根据上面的流程执行,预期来说应该是事物1的第一条select查询出一条数据,第二个select查询出两条数据(包含事物2提交的数据)。
但是在实际测试中发现第二条select实际上也只查询处理一条数据。这是但是根据数据库理论的可重复读的实现(排他锁和共享锁)这是不应该的情况。
在了解实际原因前我们先复习下事物的相关理论。
数据库原理理论 事物事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。在关系数据库中,一个事务可以是一组SQL语句或整个程序。
为什么要有事物一个数据库事务通常包含对数据库进行读或写的一个操作序列。它的存在包含有以下两个目的:
为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库在异常状态下仍能保持一致性的方法。
当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,保证彼此的操作互相干扰。
事物特性事务具有4个特性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID 特性。
原子性(atomicity):
一个事务应该是一个不可分割的工作单位,事务中包括的操作要么都成功,要么都不成功。
一致性(consistency):
事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation):
一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据在事物未提交前对并发的其他事务是隔离的,并发执行的各个事务之间不能互相影响。
持久性(durability):
一个事务一旦成功提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
事物之间的几个特性并不是一组同等的概念:
如果在任何时刻都只有一个事物,那么其天然是具有隔离性的,这时只要保证原子性就能具有一致性。
如果存在并发的情况下,就需要保证原子性和隔离性才能保证一致性。
数据库并发事物中存在的问题如果不考虑事务的隔离性,会发生以下几种问题:
脏读:脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。
不可重复读:不可重复读是指在对于数据库中的某条数据,一个事务范围内多次查询返回不同的数据值(这里不同是指某一条或多条数据的内容前后不一致,但数据条数相同),这是由于在查询间隔,该事物需要用到的数据被另一个事务修改并提交了。不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了其他事务提交的数据。需要注意的是在某些情况下不可重复读并不是问题。