1、如果当两个用户对同一个账户进行读写操作的时候,可能会出现如下的错误信息,这种情况称为“丢失修改”。其实原因就是因为没有加锁导致的。
2、排他锁。当某个用户需要写数据的时候,就添加一把锁,修改后方案如下所示:
3、脏数据
因为锁只有在写数据的时候用到,而读数据的时候是不用加锁的。那么如果出现如下这种情况:
很显然,这里就出现了脏数据。那如果在读数据的时候也添加锁呢?这样又感觉太过于繁琐了
4、共享锁:解决脏数据的问题
共享锁专门用于共享数据的读取,这个锁和之前的排他锁有区别,主要用于读取数据,如果一个数据加了排他锁,就没法加共享锁,同样加了共享锁,就没法加排他锁。然后读数据之前先加共享锁,读完之后立即释放共享锁。
(如下图所示:旺财先获取到了A用户的排他锁,然后当小强需要读取A账户的信息的时候,先添加了一个共享锁,而根据定义,一个数据加了排他锁后,没法加共享锁的,所以此时小强是无法获取到用户A的排他锁的。----问啥不直接都用排他锁?难道是因为添加排他锁的资源消耗太多了?)
5、共享锁导致的没法重读问题:
也就是说,当旺财处于某个事务中的时候,有可能会存在两次读取同一个用户的值不一样。这个问题的主要是因为旺财每次读取数据的时候用的是共享锁,而每次读完后,都会直接释放了共享锁。
那么如果要解决这个问题,就是在读取数据的时候,也需要一直锁住,直到事务提交。
6、幻读出现
排他锁:X锁
共享锁:S锁
通过上面的总结,现在一致的几点如下所示:
a、写数据时加上X锁,直到事务结束,读的时候不加锁。(由于读的时候没有加锁,所以可能读到提交或者回滚的内容,即有可能读到脏数据。这其实就是数据库最低的事务隔离级别–Read uncommitted)
b、写数据的时候加上X锁,直到事务结束,读的时候加上S锁,读完数据立刻释放。这能避免丢失数据和脏数据,但是会出现不可重复读的问题,这是第二级的事务隔离级别–read committed
c、写数据的时候加上X锁,直到事务结束,读的时候加上S锁,也是直到事务结束,这能避免丢失数据和脏数据以及不可重复读的三个问题,这是数据库常用的隔离级别–Repeatable read
出现幻读的情况:
用户A对学生表进行操作,选取了年龄为18岁的所有行数据,然后用X锁锁住,并且做了修改。改完以后A用户再次选择年龄是18岁的所有行,想做一个确认,但是没想到有一行竟然没有修改!原来在这个过程中,用户B也对学生表进行操作,插入了一个新的行,其中的年龄也是18岁。-----所以本来用户A是想对所有18岁的用户操作的,但是这个A刚刚查询出所有的18岁的数据后,用户B又插入了一条18岁的数据,相当于A用户出现了幻读。
避免出现幻读:
用户之间操作为串行。
所以总结出数据库的事务隔离界别如下所示:
7、MVCC(多版本并发控制)
使用串行化隔离级别,虽然不会出错,但是效率实在是太低。所以还是退到了可重复读。(可重复读存在幻读的情况,但是可以接受)
实现可重复读,需要在事务中对读操作加锁,并且持续到整个事务结束。那有什么办法可以在读的时候不用加锁,也能实现可重复读呢?
这就是MVCC–多版本并发控制。