孙宇的技术专栏 大数据/机器学习

MySQL 锁

2013-06-24

阅读:


MySQL锁机制

服务器并发时,会用一套锁机制来控制请求,以防数据出现混乱。

锁有两种:读锁和写锁。

读锁也称共享锁,加上该锁时其他人不受影响,都可以读取数据。

写锁加上后其他锁就再不能加上去了,也就是其他人不能再进行读取和变更,所以它又称:排他锁。

写锁比读锁拥有更高的优先级,即使有读操作用户在排队的队列中,一个被申请的写操作仍可排列在队列的前面。写锁会被安置在读锁之前,读锁不能排在写锁前。

但什么时候加锁,锁哪些数据。要有相应的策略,因为加锁解锁也要系统开锁,策略不当会直接影响服务的性能。通常有两种策略:表锁和行锁。行锁较常用。

表锁

开销最小,因为它不用去找出某一行记录然后去给它加锁,而是直接把整个表加上锁标记。当用户对表进行写(插入,删除,更新)时,用户获得一个写锁,它会禁止其它任何用户的读和写操作。只有无人操作时,用户才能获得读锁。读锁和读锁之前不冲突。

行锁

行锁可以最大程度的支持并发,当然开销也更大。行锁只能在 InnoDB 和 Falcon 引擎中被实现。行锁是由引擎自己实现的,不是 MySQL 自身支持的。

多版本并发控制

大多事务型引擎除了用行级锁外,还用一种叫 “多版本并发控制MVCC”Multiversion Concurrency Control 的技术,和行锁关联使用。它不是MySQL 专用的,Oracle, PostSQL 及其它数据库也使用。

它是一种锁的变形,避免很多情况的加锁操作,大大降低系统开销。每种存储引擎实现MVCC的方式不一样。

InnoDB 实现方式

为每个数据行增加两行隐含值,用来记录行的创建时间及过期时间(删除时间,实际上是版本号)。每一行都存储了事件发生时的版本号,用来代替事件发生时的实际时间。开始一个新事务时,版本号自增。每个事务都会保存它在开始时的 “当前系统版本”的记录,而每个查询都会根据事务的版本号,检查每行数据的版本。

实例:

Select 时:

InnoDB 只找版本早于当前事务版本的行。这确保了事务读取的行都是在事务开始前已经存在的,或者由当前事务创建或修改的行。

且数据行的删除版本必须是未定义或者大于事务版本,这保证了事务读取的行在事务开始时是未被删除。

Insert 时: 为每个新增行记录当前系统版本号。

Delete 时: 将当前系统版本号作为行的删除标识。

Update 时: 为要更新的行建立一个拷贝,并在新的拷贝记录当前系统版本号。同时为更新前的旧行记录系统版本号作为删除标识。

保存额外的记录使其它事务的读取不必申请加锁,这使读操作变得更快,因为只需要按当前版本号去取相应的数据即可。但这种方式的缺点是存储引擎必须为每行都存储额外的数据,做更多检查,以及整理。

索引可以让查询锁定更少的行.InnoDB 只有在访问行的时候才会对其加锁,而索引能够减少访问的行数,从而减少锁的数量.

InnoDB 存储引擎在检索到数据并返回给服务器层后,MySQL 服务器才能应用 where 语句,而InnoDB 的行锁机制是引擎实现的,而不是 MySQL 服务器.

所以,在返回所有数据时,这些行就已经锁定了,当 MySQL 服务器过滤掉不需要的数据后,这些行才会被引擎释放锁.


上一篇 MySQL 索引

下一篇 高可用架构

评论

文章