MySQL-InnoDB-事务

事务的隔离级别和锁机制:

  READ UNCOMMITTED(未提交读)

    在这个级别,事务中的修改,即使没有提交,对其他事务也都是可见的,事务可以读取未提交的数据。(不加锁或只加共享锁)

  READ COMMITTED(提交读)

    一个事务开始时,只能“看见”已经提交的事务所做的修改。也就是一个事务从开始直到提交前,所做的任何修改对其他事务都是不可见的。(对行记录加排它锁)

  REPEATABLE READ(RR可重复读)     MySQL数据库默认的隔离级别

    两个事物:A, B 事物A插入一条数据或者更新一条数据,并且提交了事物,这个时候事物B还是读取不到事物A修改的数据。要事物B也提交之后才能看到事物A修改的数据。就是说要事物A和B都commit之后,事物B才能看

            到事物A提交的数据。可重复读解决了“脏读”的问题,但是有“幻读”的问题,

                                                                   

RR案例一:
事务A 事务B 说明
BEGIN;   事务A开启
  BEGIN; 事务B开启
UPDATE table SET name='xxx' where id=1   事务A更新数据
SELECT * FROM table   事务A查询数据,能查到更新后的
  SELECT * FROM table 事务B查询数据,查询不到事务A更新的数据
COMMIT;   事务A提交
  SELECT * FROM table 事务B查询数据,查询不到事务A更新的数据
  COMMIT; 事务B提交
  SELECT * FROM table 事务B查询数据。可以查询到事务A更新的数据

                                                                    

RR案例二:
事务A 事务B 说明
BEGIN;   事务A开启
  BEGIN; 事务B开启
UPDATE table SET name='xxx' where id=1   事务A根据id更新数据,但是还没有提交
  UPDATE table SET name='xxx' where id=1 事务B根据id更新数据,会卡住不动。如果事务A一直不提交,最后超时
COMMIT;   事务A提交,事务B的更新才能成功
  COMMIT;  

 

 

 

 

 

 

 

 

             

    InnoDB和XtraDB存储引擎通过MVCC解决了幻读的问题。(对符合条件的记录加区间锁)

  SERIALIZABLE(可串行化)    ORACLE数据库默认的隔离级别

    一个事务在执行过程中完全看不到其他事务对数据库所做的更新,当两个事务同事操作数据库中相同的数据时,如果第一个事务已经在访问该数据,第二个事务只能停下

    来等待,必须等到第一个事务执行完毕后才能够进行。最高的隔离级别,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁竞争的问题。(对整个表加锁)

 

                          

  1. MySQL可以通过执行SET TRANSACTION ISOLATION LEVEL命令来设置隔离级别。新的隔离级别会在下一个事务开始的时候生效。

  2. 也可以改变当前回话的隔离级别:SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

  3. MySQL服务器层不管理事务,事务是由下层存储引擎实现的。

事务设置的相关命令:

  1、查看当前会话的隔离级别:select @@tx_isolation;

  2、查看系统当前隔离级别:select @@global.tx_isolation;

  3、设置当前会话隔离级别:set session transaction isolation level repeatable read;

  4、设置当前系统隔离级别:set global transaction isolation level repeatable read;

  5、查看和设置mysql自动提交:show VARIABLES like 'autocommit';  set autocommit=off;

脏读:

  允许事务B读到了事务A未提交的数据,可能就造成了脏读,脏读的本质就是无效的数据,只有当事务A回滚,那么事务B读到的数据才为脏数据,所以这里只是可能造成脏读。如果事务A不回滚,事务B读到的数据就不为脏数据,也就是有效的数据。(脏读只会在读未提交的情况下发生)

                                                                                        

不可重复读:

  不可重复读,一个事物只能读取到另一个事物已经提交的数据,就是指在一个事务范围中2次或者多次查询同一数据M返回了不同的数据,例如:事务B读取某一数据,事务A修改了该数据M并且提交,事务B又读取该数据M(可能是再次校验),在同一个事务B中,读取同一个数据M的结果集不同。(不可重复读在读未提交和读已提交的事物隔离级别都有可能发生)

                        

幻读:

  当用户读取某一个范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现会有新的“幻影行”,例如:事务B读某一个数据M,事务A对数据M增加了一行并提交,事务B又读数据M,发生多出了一行造成的结果不一致(幻读在读未提交、读已提交、可重复度的事物隔离级别都有可能发生)。

                        

丢失更新:

  事务A和事务B,同时获得相同数据,然后在各自的事务中修改数据M,事务A先提交事务,数据M假如为M+,事务B后提交事务,数据M变成了M++,最终结果变成M++,覆盖了事务A的更新。

                        

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

  1、简单来说,不可重复读是由于数据修改引起的,幻读是因为数据增加或者删除引起的。

  2、不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。

  3、所谓幻读,是指事务A读取与搜索条件相匹配的若干行。事务B以插入或删除行等方式来修改事务A的结果集,然后再提交。

隐式锁定和显式锁定:

  1.InnoDB采用的是两阶段锁定协议(two-phase locking protocol)。在事务执行过程中,随时都可以执行锁定,锁只有在执行COMMIT和ROLLBAK的时候才会释放,并且所有的锁是在同一时刻被释放。

  2. LOCK TABLES和事务之间相互影响的话,情况会变得非常复杂,所以除非事务中禁用了AUTOCOMMIT,可以使用LOCK TABLES之外,其他任何时候都不要显示的执行LOCK TABLES,不管使用的是什么存储引擎。

死锁:

  两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环现象。当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁。多个事务同时锁定同一个资源也可能会产生死锁

  例如:

--事务1
START TRANSACTION;
UPDATE price SET close=45.5 WHERE stock_id=4 AND date='2017-10-11';
UPDATE price SET close=19.8 WHERE stock_id=3 AND date='2017-10-12';
COMMIT;

--事务2
START TRANSACTION;
UPDATE price SET high=20.12 WHERE stock_id=3 AND data='2017-10-12';
UPDATE price SET high=47.20 WHERE stock_id=4 AND data='2017-10-11';
COMMIT;

 

  如果凑巧,两个事务都执行了第一条UPDATE语句,更新了一行数据,同时也锁定了该行数据,接着每个事务都尝试去执行第二条UPDATE语句,却发现改行已经被对方锁定,然后两个事务都等待对方释放锁,同时有持有对方需要的锁,则陷入死循环。除非有外部因素接入才可能接触死锁。InnoDB目前处理死锁的方法时,经持有最少行级排他锁的事务进行回滚

 

InnoDB-MVCC多版本并发控制

 事物和索引的关系?

参考:

 【1】《高性能MySQL》(第三版), Baron Schwartz等 著,宁海元等 译,电子工业出版社 ,2013

 【2】 博客,https://segmentfault.com/a/1190000004469395#articleHeader6

 【3】微信,https://mp.weixin.qq.com/s/LlgYXE7oswDJEt5wJhyAwA

 【4】https://developer.aliyun.com/article/743691

posted @ 2017-10-24 19:15  寻找风口的猪  阅读(473)  评论(1编辑  收藏  举报