事务学习总结(1)——事务的基本概念

一:什么是事务?

    对数据库读写一系列操作的合集。

    具有"ACID"的特性,即原子性、一致性、隔离性、持久性。

    核心点是锁与并发。

二:主要用在哪些场景?解决了什么问题?

    主要用于数据层面,通过约定事务的规则来保证数据的可靠性、有效性。
    主要解决了脏读、不可重复读、幻读的问题。

三:ACID?

     原子性(Atomicity):对数据库一系列操作,具有不可分割的特征,要不一起执行要不都不执行(回滚)。就像我们在化学课里学到的原子,原子是构成物质的最小单位。

    一致性(Consistency):执行完数据库操作,数据不会被破坏。比如银行实时转账,A向B转100元,用户看到结果是转账成功(A少了100元,B多了100元),转账失败(A、B的余额都没有变化)。但是不会看到说中间状态(A少了100元,B没有变化)。

    隔离性(Isolation):多条事务并发操作时,一个事务的操作不应影响其他事务的执行。约定了4个隔离性级别,读未提交、读已提交、可重复读、序列化,从前往后级别越来越高、并发性越来越差、安全性越来越高。

   持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。数据库发生故障时,确保提交的事务不丢失,未提交的事务可以正常进行回滚。通过记录数据库操作日志来保证。

四、隔离性详细说明:

   1、读未提交:事务A读取到事务B未提交的数据。存在的问题:脏读、不可重复读、幻读。

   2、读已提交:事务A读取到事务B已提交的数据。例如:事务A在两次读操作之间,事务B对数据进行了修改并完成了提交,事务A两次读取的结果不一致。解决的问题:脏读。存在的问题:不可重复读、幻读。

   3、可重复读:事务A多次读取的数据值是一样的。其中可重复读是通过mvcc来实现的又叫快照读,在事务中的读操作通过对当前的数据库中记录一个版本,以后的读操作只会读取记录的版本,因此相当于对数据库的数据建立了一个快照数据,因此叫做快照读,其不用对数据库中的数据进行加锁又叫做乐观锁。解决的问题:脏读、不可重复读。存在的问题:幻读。

   4、可序列化:将所有的事务排队,利用排他锁的方式,将事务锁住,单位时间内,只有一个事务进来。解决的问题:脏读、不可重复读、幻读。

五、三类数据读问题:

   1、脏读:事务A读取到事务B未提交的数据。在“读未提交”级别会出现,“读已提交”及以上级别解决了这个问题。

   2、不可重复读:事务A在两次读操作之间,事务B对数据进行了修改并完成了提交,事务A两次读取的结果不一致。在“读已提交”及以下级别会出现,“可重复读”级别解决了这个问题。

   3、幻读:A事务读取B事务提交的新增数据会引发幻读问题。幻读一般发生在计算统计数据的事务中,例如银行系统在同一个事务中两次统计存款账户的总金额,在两次统计中,刚好新增了一个存款账户,存入了100,这时候两次统计的总金额不一致。在“可重复读”及以下级别会出现,“可序列化”级别解决了这个问题。

    不可重复读和幻读的区别:

             不可重复读已经提交的事务的更改数据(修改或删除)

             幻读:指读到了其他已经提交事务的新增数据

             在可重复读的隔离级别,只会在已经存在的行加上行锁,而不会增加表锁。因为针对新增的数据,行锁是无效的,所以会产生幻读。

六、两类数据更新问题:

    1、第一类丢失更新。A事务撤销时,把已经提交的B事务的更新数据覆盖了。在当前的四种任意隔离级别中,都不会发生该情况。

    2、第二类丢失更新。B事务覆盖A事务已经提交的数据,造成A事务所做操作丢失。在“读未提交”、“读已提交”级别会发生。

七、总结:

八、MVCC(多版本控制模型):

    “读未提交”级别产生的脏读,基本上是不被允许的。“可序列化”级别的性能太差,基本也不会被使用。那么主流就在“读已提交”、“可重复读”两个级别进行选择,并进行相应的性能优化。“读已提交”级别会产生“第二类丢失更新”问题(B事务覆盖A事务已经提交的数据,造成A事务所做操作丢失),因此mysql数据库默认选择的隔离级别是“可重复读”级别,同时采用MVCC模型优化了系统性能。

     其中可重复读可以做到读读并行,读已提交写锁可以将读锁升级。在这“读未提交”事务隔离级别下,如果当前事务正在写,那么其它所有的读都将被阻塞(这里的读写事务是针对相同的资源,或者说是针对数据库的同一行数据),所以优化的点也在这里,有没有办法让写不阻塞读呢?这样的话,可以大大提升数据库读的性能,尤其是在读多写少的场景下,这样的性能优化尤其重要。

    MVCC(多版本并发控制)模型为解决这个问题提供了思路。在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。

那哪些读操作是快照读?哪些操作又是当前读呢?以MySQL InnoDB为例:

快照读:简单的select操作,属于快照读,不加锁:

select * from table where A=?;

当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。

select * from table where A=? lock in share mode;

select * from table where A=? for update;

insert into table values (…);

update table set A=? where B=?;

delete from table where A=?;

所有以上的语句,都属于当前读,读取记录的最新版本。并且读取之后,还需要保证其它并发事务不能修改当前记录,对读取记录加锁。其中除了第一条语句,对读取记录加S锁 (共享锁)外,其它的操作,都加的是X锁 (排它锁)。

猜你喜欢

转载自blog.csdn.net/luoliang2012/article/details/82011213