数据库并发问题与隔离级别
1 并发产生的问题
数据库的事务在并发执行的时候,如果不考虑隔离性,就会产生以下几种问题:
1.1 脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
假设事务1正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,事务2也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么事务2读到的这个数据是保存在数据库内存中的数据,称为脏读。读到的数据为脏数据,依据脏数据所做的操作可能是不正确的
1.2 不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
在事务1内,多次读同一个数据。在事务1还没有结束时,事务2也访问该同一数据并修改数据。那么,在事务1的两次读数据之间。由于事务2的修改,那么事务1两次读到的数据可能不一样,这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复。
相比起脏读,不可重复读读取的是另一个已经提交的事务,而脏读读取的是还未提交的事务。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,从而引发错误
1.3 幻读
幻读是指当事务不是独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)
2 数据库的隔离级别
为了避免以上问题,防止事务被其他事务干扰,因此多个并发的事务之间需要相互隔离。隔离等级分为4个级别,由低到高分别是为:
2.1 读未提交(Read uncommitted)
允许读取未提交的数据。此时,可能会发生脏读、不可重复读、幻读。这是并发最高,但也是一致性最差的隔离级别
2.2 读已提交(Read committed)
只允许读取已提交的数据。可以避免脏读,但无法避免不可重复读和幻读
2.3 可重复读(Repeatable read)
只允许读取已提交的数据,并且在一个事务两次读取一个数据项期间,其他事务不得更新数据。可以避免脏读和不可重复读,无法避免幻读。这也是MySQL默认的隔离级别
2.4 串行化(Serializable )
保证所有的事务串行化调度。这种隔离级别可以避免脏读、不可重复读、幻读
以表格形式整理:
隔离级别 | 是否存在脏读 | 是否存在不可重复读 | 是否存在幻读 |
---|---|---|---|
读未提交 | 是 | 是 | 是 |
读已提交 | 否 | 是 | 是 |
可重复读 | 否 | 否 | 是 |
串行化 | 否 | 否 | 否 |