当数据库中多个事务(Transaction)处理同一数据时,就会出现并发的问题,也就是需要解决数据库隔离性的问题(isolation)。
数据库的事务操作主要会碰到以下几类问题:
1.脏读:脏读指的是当前事务读到了其他事务未提交(uncommitted)的数据;
2.不可重复读:本处的不可重复指的是在同一事务中,本事务未修改数据的情况下,两次读取的数据不一致;
3.虚读:虚读类似于不可重复读,只不过读取的不是数据库中某一行数据,而是一类数据,因此其余事务即使只是插入新的数据,也会对本事务的读产生影响;
4.第一类更新丢失:第一类更新丢失值得是,某一事物回滚(rollback)导致其他事务提交的数据被覆盖;
5.第二类更新丢失:本质和不可更新读一样,出现于不知道其他事务更新操作的存在。
知道了,以上的几个问题,我们来看看数据库事务的隔离级别是如何解决这些问题的:
1.Read uncommitted 读未提交数据:能解决第一类丢失更新的问题,但不能解决脏读的问题
实现原理是,读数据时候不加锁,写数据时候加行级别的共享锁,提交时释放锁。行级别的共享锁,不会对读产生影响,但是可以防止两个同时的写操作。
2.Read committed 读提交数据:能解决脏读的问题,但是不能解决不可重复读的问题:
实现原理是,事务读取数据(读到数据的时候)加行级共享锁,读完释放;事务写数据时候(写操作发生的瞬间)加行级独占锁,事务结束释放。由于事务写操作加上独占锁,因此事务写操作时,读操作也不能进行,因此,不能读到事务的未提交数据,避免了脏读的问题。但是由于,读操作的锁加在读上面,而不是加在事务之上,所以,在同一事务的两次读操作之间可以插入其他事务的写操作,所以可能发生不可重复读的问题。
3.Repeated Read 可重复读:顾名思义,可以解决不可重复读的问题,但是不能解决虚读问题:
实现原理,和读提交数据不同的是,事务读取数据在读操作开始的瞬间就加上行级共享锁,而且在事务结束的时候才释放。分析方法和读提交数据类似,本处不再赘述。但是,由于加锁只是加在行上,所以,仍然可能发生虚读的问题。
4. Serializable 串行化:可以解决以上所有的并发问题:
实现原理是,在读操作时,加表级共享锁,事务结束时释放;写操作时候,加表级独占锁,事务结束时释放。