原文地址: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()实现这个逻辑。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。