MySQL数据库InnoDB存储引擎中的锁机制--转载

原文地址:http://www.uml.org.cn/sjjm/201205302.asp

一个资源的时候,有可能导致数据不一致。因此需要一种致机制来将访问顺序化。

一个比喻。试衣间供许多消费者使用。因此可能有多个消费者同时要试衣服。为了避免冲突,试衣间的门上装了锁。试衣服的人在里边锁住,其他人就不能从外边打开了。只有里边的人开门出来,外边的人才能进去。

数据库上的操作可以归纳为两中,读和写。多个事务同时读一个对象的时候,是不会有冲突的。

共享锁(Shared Lock) 也叫读锁.

共享锁表示对数据进行读操作。因此多个事务可以同时为一个对象加共享锁

一个事务对对象加了排他锁,其他事务就不能再给它加任何锁了。

一个矩阵来描述他们之间的冲突关系。

修改表结构。

间的冲突,就引入了意向锁。

修改表结构。

一个隐含的逻辑:

用户的使用情况相关,有些情况下是用户能接受的,有些情况下是用户不能接受的。

MysqL手册中有幻读的介绍.

间的间隙,来阻止INSERT操作。

代码中称作Precise Mode。这些精确的模式,使的锁的粒度更细小。可以减少冲突。

代码中称为Ordinary Lock),同时锁住记录和间隙.

代码中,插入意图锁,

一个LOCK_INSERT_INTENTION的标记.

MysqL手册对这些模式有详细的介绍.

包括等待的锁)

代码推出来的。从这个矩阵可以看到几个特点:

标记的方式,能否直接变成INSERT_INTENTION锁?

MysqL手册有详细的介绍。

一个session并发插入(2,5,2),2)时可以成功,但是(2,2,2)时会被阻塞。

方法。在使用这种方法时,遍历了所有的数据,因此所有数据都被锁住了。尽管对不符合条件的记录调用了ha_innobase::unlock_row(),但是在Repeatable Read级别时不会被释放。也许该算一个Bug.

一个大于符合条件的记录)上。而Next-Key加在所有符合条件的记录上。上面例子中的条件c2=2的记录,需要在c2=3上加一个GAP锁。

查询时,InnoDB中实际上在边界上加的是Next-Key锁。 这可能是受实现的限制。

一个GAP锁

查询(ORDER BY DESC)时.

一个确切的键值时,对下一条记录加GAP锁。

一个确切的键值的前缀时,对下一条记录加GAP锁。。

一个插入意图锁。这个锁是在waiting状态。

查询一个唯一的值,如 WHERE c1 = 1,c1 是主键或唯一键,并且查询结果中不含NULL字段。

binlog被开启。这里还是有一些值得思考的问题:

  • 从这个情况来看,UPDATE,DELETE时加间隙锁完全是为了防止Master和Slave数据不一致。那么不使用binlog时就没有必要对DELETE,UPDATE加间隙锁。
  • Row Format binlog时,不加间隙锁是否会引起Master,Slave不一至。
  • 即便设置了innodb_locks_unsafe_for_binlog,SELECT…[]是否可以不加间隙锁。

MysqL()中。

一个表有很多的索引,那么操作一个记录时,岂不是要加很多锁到不同的B-Tree上吗?

一个事务的状态信息:

一个延迟加锁的机制,来减少加锁的数量,在代码中称为隐式锁(Implicit Lock)。

一个隐含的trx_id字段,这个字段存在于簇索引的B+Tree中。

添加一个锁)。

代码:

显示锁。

一个参数表示是否是隐式锁。所以要特别注意这个参数。如果为TRUE,在没有冲突时并不会加锁。

内容在lock_rec_has_wait()

数量。

修改的B+Tree记录,因此都是Record类型的锁。不可能是Gap或Next-Key类型。

显示加锁。

查询时,直接对查询用的Index和主键使用显示锁,其他索引上使用隐式锁。

显示锁应该是为了减少死锁的可能性。

一个优化:

一个MAX_TRX_ID,每次修改辅助索引的记录时,都会更新这个最大事务ID。

页面的max_trx_id和事务列表的最小trx_id比较。如果max_trx_id比事务列表的最小trx_id还小,那么就不需要转换为显示锁了。

代码在lock_sec_rec_some_has_impl_off_kernel()中

= min trx id for the trx list,ordatabase recovery is running. We do not write the changes of a page max trx id to the log,and therefore during recovery,this value for a page may be incorrect. */

locks 存放一个表的所有表级锁。

rec_hash存放所有表的行锁。Hash值根据(spaceid,pageno)来计算。

trx_locks存放事务的所有锁,包括表级锁和行级锁。一个事务的所有锁,在事务结束时,一起释放。代码在lock_release_off_kernel().如果有等待的锁可以被授权,则会将等待的锁,转变为被授权的锁,并唤醒相应的事务。

页面上的一个自增数值。每条物理记录在被创建时,都会分配一个唯一的heap no.

一个逻辑值,page no. + heap no. 是物理的。

一个B+Tree页面时,一半的记录要移到新的页面中,因此要对存在的锁进行迁移。

函数有:lock_move_reorganize_page(),lock_move_rec_list_start(),

删除和插入数据时,也要进行GAP锁的继承。lock_rec_inherit_to_gap()

添加一个waiting锁,并且返回DB_LOCK_WAIT错误

MysqL_handle_error调用srv_suspend_MysqL_thread来挂起一个线程。

调用lock_deadlock_occurs()进行死锁的检测。

方法是Waits-For Graph.在lock_deadlock_recursive()中实现。

一个事务,将其回滚,来解除死锁。选择哪一个事务回滚能?

一个事务修改了non-transactional表(如MyISAM表,修改不能回滚),另一个表没有。

修改non-transactional的会被回滚。

修改了non-transactional表或者都没有。则比较2个事务修改的记录数和加的锁数量。总和小的事务会被回滚。trx_weight_ge()实现这个逻辑。

相关文章

MySQL 死锁 是指两个或多个事务互相等待对方持有的锁,从而导...
在MySQL中,InnoDB引擎通过Next-Key Locking技术来解决幻读问...
在数据库事务管理中,Undo Log 和 Redo Log 是两种关键日志,...
case when概述 sql语句中的case语句与高级语言中的switch语句...
其实很简单,只是为了忘记,做个记录,用的时候方便。 不管是...
1.进入服务,找到mysql服务,在属性里找到mysql的安装路径 2...