事务的隔离性
数据库的事务有四大特性:原子性,一致性,隔离性,持久性。其中隔离性指的是在有多个事务在一个数据库上同时执行时,不会造成数据的不一致。理想状态下,事务应该互不干扰。可是要实现这一点并不容易,必须要通过数据库锁机制配合,这就会带来极大的性能开销。所以,就有了数据库隔离级别的概念,不同隔离级别下事务之间的影响程度不同,这样就可以根据业务的需要,选用合适的隔离级别,平衡隔离性和系统开销。
三大问题
我们首先来看一下的多事务并发场景下,可能会出现的三大问题。
脏读
脏读指的是一个事务未提交之前,它对其他事务的修改就可以被其他事务查询到,如果这时这个事务回滚,丢弃了对记录的修改,那其他事务得到是记录就可能和数据库实际存储的记录不一致。如下图,
事务B回滚,它对v1的修改是无效的。但是因为在回滚之前,它对v1的修改就被A看到了,所以事务A第二次查询的v1值不是数据库中的真实记录,也就是说这个数据是“脏的”。所以这种情况就叫脏读。
解决方法:要解决这个问题其实很简单,只要规定在事务提交之前,它对数据所做的修改不能被其他事务看见就可以了。
不可重复读
不可重复读指的是在一次事务中,因为其他事务对数据的修改,造成读取同一条数据的结果不一致,如下图:
事务A两次查询v1的结果是不一样的,因为事务B修改过了v1。
解决方法:要想解决不可重复读的问题,就要规定一个数据从启动到开始,它所读到的数据是一致的。实际上,数据库是通过在事务启动时创建视图,来保证数据一致性的。
幻读
幻读和不可重复读有点像,但它对应的不是一条具体的数据,而是一个范围内的数据,也就是说,造成幻读不是因为对数据的修改,而是插入数据和删除数据,如下图:
因为事务B新插入了一条新记录,找出两次范围查询的结果不一致,就好像出现了幻觉一样,所以这种情况下被称为幻读。
解决方法: 幻读和不可重复读很像,但是解决方法却不同,因为不可重复读是针对一行的问题,所以可以通过行锁解决,幻读针对的是一个范围的问题,所以要对一个范围上锁。
四大隔离级别
看过了事务并发场景下的三种问题,我们再来认识一下四大隔离级别,实际上,它们就是就针对了上面提出的问题。
- 读未提交:读未提交指的是事务未提交之前就可以被其他事务看见,该隔离级别隔离性最低,无法解决上述三大问题中的任何一个。
- 读已提交:该隔离级别下,事务提交之前,对其他事务是不可见的,它可以解决脏读,但不可以解决不可重复读和幻读。
- 可重复读: 在一个事务内,对同一记录的读取结果都是相同的。它可以解决脏读和不可重复读,但不能解决幻读。
- 可串行化: 隔离性最高的隔离级别,该隔离级别下,事务执行过程中会被锁住,其他事务必须等该事务执行完毕才能继续执行,这种情况下就好像事务不是并行,而是串行的,它可以解决三大问题,但是效率很低,很少用。
数据库会根据不同的业务使用不同的隔离级别。