假如有两个事务并发,顺序如下:
那么在事务A中,query1跟query2查询出来的结果是否一样呢?这就跟事务隔离级别有关了。
SQL的标准定义里面,一共有四种级别:
1. read uncommited :读取未提交的数据.就是其他事务已经修改但还未commit的.
2. read commited :读取已提交的数据query2会跟query1读取的数据不一样.
3. repeatable read :可重复读取,即query1跟query2读取的数据是一样的.
4. serializable :序列化.
SQL 标准用三个必须在并行的事务之间避免的现象定义了四个级别的事务隔离。
这些不希望发生的现象是:
1. 脏读(dirty reads):一个事务读取了被另一个事务改写但还没提交的数据.
2. 不可重复读(non-repeatable reads):一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过(一个事务执行相同的查询两次或两次以上,但每次查询结果都不同时。这由于另一个并发事务在两次查询之间更新(update)了数据).
3. 幻读(phantom read):在两次查询同一时间点数据时,发现数据数量发生改变。(当一个事务读取几行记录后,另一个并发事务插入(insert,delete)一些记录).
SQLServer
我们首先在SQLServer上做了实验,SQLServer一共支持四种隔离级别,read uncommited跟read commited我们没有实验,我们直接先实验repeatable read.
如果事务A定义了如下级别,那么当事务B执行到modify1这条语句时,如果modify1是update的话,就被锁起来,一直等到事务A提交完以后,锁才会被释放。
而如果是insert的话,则可以顺利进行下去,然后在事务A中,query2查到的数据,是已经被事务B修改过的数据。(发生了幻读)
如果将级别定义在serializable的话,则在modify1语句中,update,insert或者delete都会被锁掉。也就是说,SQLServer对这些级别的支持,是通过锁来做到的,虽然可以保证事务正常进行,但是并行的性能却很差。
Oracle
oracle只支持两个级别,read commited跟serializable,实验的结果是,oracle的serializable是通过版本控制来完成的,而不是通过锁机制,这就保证了并行的性能。Oracle的
默认级别是read commited.
Mysql
MySQL也支持四个级别,而且MySQL也是通过版本控制而非锁机制来完成的。
假如有两个事务并发,顺序如下:
MySQL默认使用的是REPEATABLE READ .Transaction A 的 第 1,2,3次query都是一样的。(query3好像没有发生幻读,不知道什么原因,研究中),只有第query4才显示Transaction B刚刚insert的数据Transaction A query3的时候可以通过SELECT * FROM t LOCK IN SHARE MODE; 来获取Transaction B刚刚insert并且commit的数据。但是如果Transaction B一直没有commit,query3会持续等待,不能读取。