数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。按照数据库的理论,隔离级别可以被分为以下四种,从上向下依次增强。
一、数据库的事务隔离与锁机制有什么差别和联系
数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。
按照数据库的理论,隔离级别可以被分为以下四种,从上向下依次增强:
读不提交,造成脏读(Read Uncommitted): 一个事务中的读操作可能读到另一个事务中未提交修改的数据,如果事务发生回滚就可能造成错误。
例子1:A打100块给B,B看账户,这是两个操作,针对同一个数据库,两个事物,如果B读到了A事务中的100块,认为钱打过来了,但是A的事务最后回滚了,造成损失。
例子2:游戏当中剩余挑战次数,读取次数是个事务中的操作,如果写同时并发,则可能导致两个事务同时修改数据,同时读到数据是1,但是当再次修改的时候就一个事务修改为0,另一个事务修改为1,就可能造成误判。
避免这些事情的发生就需要我们在写操作的时候加锁,使读写分离,保证读数据的时候,数据不被修改,写数据的时候,数据不被读取。从而保证写的同时不能被另个事务写和读。
读提交(Read Committed):我们加了写锁,就可以保证不出现脏读,也就是保证读的都是提交之后的数据,但是会造成不可重读,即读的时候不加锁,一个读的事务过程中,如果读取数据两次,在两次之间有写事务修改了数据,将会导致两次读取的结果不一致,从而导致逻辑错误。
Repeatable Read(可重读):解决不可重复读问题, 一个事务中如果有多次读取操作,读取结果需要一致(指的是固定一条数据的一致,幻读指的是查询出的数量不一致)。 这就牵涉到事务中是否加读锁,并且读操作加锁后是否在事务commit之前持有锁的问题,如果不加读锁,必然出现不可重复读,如果加锁读完立即释放,不持有,那么就可能在其他事务中被修改,若其他事务已经执行完成,此时该事务中再次读取就会出现不可重复读,所以读锁在事务中持有可以保证不出现不可重复读,写的时候必须加锁且持有,这是必须的了,不然就会出现脏读。Repeatable Read(可重读)也是MySql的默认事务隔离级别,上面的意思是读的时候需要加锁并且保持
Serializable(可串行化) : 解决幻读问题, 在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。 这是较高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
下面文章进一步说明了锁与事务隔离的关系,并实例验证了读未提交可以同时读,并且一个事务可以读取到另一个事务未提交的修改,但是不能在另一个事务未提交修改的时候同时修改相同的行;
读提交则可以保证不会读取到另一个事务未提交的修改;
同理可以验证幻读的问题。
延伸阅读:
二、事务隔离级别是什么
事务具有ACID属性,而事务的隔离级别可以不同程度的解决事务并发时可能产生的问题,可以根据不同业务逻辑需求,来选择不同的事务隔离等级,事务隔离等级越高,越能保证数据的一致性,但就更趋近于串行化,降低并发性能,导致效率变低。