Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > Innodb事务和锁

Mysql中的Innodb事务和锁详解

作者:feiyingHiei

这篇文章主要介绍了Mysql中的Innodb事务和锁详解,InnoDB是MySQL的一种存储引擎,它是一种可靠性和性能非常好的存储引擎,它具有ACID事务支持,可以提供高并发性和数据完整性,需要的朋友可以参考下

Innodb事务和锁

一. 事务隔离级别

  1. READ UNCOMMITED :读未提交,事务之间可以看到彼此之间正在修改的内容,会出现所谓的脏读现象
  2. READ COMMITED : 读已提交,只能读取已经提交的事务修改的数据,不会出现脏读的现象,但会出现不可重复读和幻读的情况
  3. REPEATABLE READ : 可重复度,在innodb中解决了不可重复读和幻读的问题
  4. SERIALIZED : 串行化, 这个使用的比较少,隔离性最强,性能也最差

二. 锁类型

监控方法

三.锁释放的时机

lock通常在事务commit或是rollback之后才会释放

四. 一致性非锁定读

这是非常常见的问题,事务中会有大量的select操作,select操作通常情况下是不会对数据做加锁操作的, 这样保证了数据的并发性能,在不同的事务隔离级别下,非一致性锁定读的行为是不太一样的

五. 加锁算法

上文描述了锁的类型,即排它锁,共享锁,意向锁之类,这里所说的是加锁的算法,即为innodb使用了什么样的加锁策略来处理实际场景中的并发问题。

netx-key lock算法主要解决的问题就是幻读问题,因此这个算法只在 RR事务隔离级别中会使用

疑问? 不是MVCC可以在无锁的情况下解决幻读的问题吗,为什么还要上next-key lock这么重的算法呢?这里就要引出两个概念了,一致性非锁定读(快照读) 和一致性锁定读(当前读) 的概念了

一致性非锁定读 : 我们平时使用的select * from table 这种查询语句,都是快照读,在innodb RC和RR级别下都是通过MVCC机制来实现的,过程中是不加锁的,读取的数据未必是当前行中的真实的数据。

一致性锁定读 : select * from table for update 或者select * from table in shared mode 在这种情况下RC基本是会对对应的行加锁,RR级别下就会使用next-key算法加锁。

六、redo日志

redo日志是物理日志,记录的页的物理修改日志

七、undo日志

undo日志是逻辑日志,记录的是操作的sql逻辑,通常我们在修改数据的时候,先对行加锁,然后将该版本的数据拷贝到undo日志中,然后修改当前行的操作事务id,修改该行事务,然后把回滚指针指向und日志。

七、MVCC

多版本控制(MVCC)在许多关系型数据库中都有实现,innodb中主要是依赖undo日志来实现,其中涉及到的一个比较重要的概念就是read veiw

无论是在什么事务隔离级别下,基于read view的快照读机制都相同的,只是创建read view的机制不太一样。

在RR基本下,read view在事务开启的时候就创建完成了,二在RC级别下,每次查询都会重新创建read view。

如果一个当前事务为事务A, 另外一个事务是事务B, 如果事务A开启的时候,事务B已经提交了,那么无论在RR级别或是RC级别下,B提交的数据对于事务A都是可见的; 如果B事务在A事务开启之前就已经开启了,但是A启动的时候B事务还没有提交,那么先让无论RR级别还是RC级别,数据在快照读模式下也都是不可见的;如果B事务在A开启之前就开启,但是在A事务提交前B事务就提交了,此时对于RR级别而言,B的trx_id在trx_ids之中(trx_ids是在开启事务的时候就已经初始化了),那么RR级别下数据是可见的,但对于RC而言,重新生成的read view了,显然数据就是可见的。

通过上述的分析,通过mvcc可以在RR级别下快照读是完全解决了重复读和幻读的问题,RC级别还是会有不可重复读和幻读的问题,但是需要注意的是,MVCC只工作在快照读(一致性非锁定读)条件下,对于当前读的问题是无法走到MVCC的,所以一定要注意,MVCC只解决了快照读的幻读和不可重复读问题。

这里需要补充一个case来理解一下快照读与当前读的巨大区别

CREATE TABLE `user_info` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL DEFAULT '',
  `age` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
)
事务隔离级别为RR

初始化数据

insert into user_info ('name', 'age') values ('jack', 1);

T1时刻A开启事务,然后启用快照读

select * from user_info where id = 1;

查询到的结果是

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | tom  |   0 |
+----+------+-----+

T2时刻我们开启事务B, 并且执行

update user_info set age =1 where id = 1;

此时事务A中执行当前读

select * from user_info where id = 1 for update;

事务A将会被阻塞 此时提交事务B,事务A中显示的查询结果为

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | tom  |   1 |
+----+------+-----+

然后我们再次执行一次快照读

select * from user_info where id = 1;

获得的结果为

+----+------+-----+
| id | name | age |
+----+------+-----+
|  1 | tom  |   0 |
+----+------+-----+

通过上述的例子,可以看到,快照读和当前读有着非常大的区别,在同一个事务当中,快照读和当前读返回的结果有可能是不一样的。

我们看到,mvcc保证了快照读每次读取的数据是一致,next-key算法保证了当前读是一致。

到此这篇关于Mysql中的Innodb事务和锁详解的文章就介绍到这了,更多相关Innodb事务和锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文