数据库行锁实现

https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html

有两种模式:

1. SELECT ... LOCK IN SHARE MODE

读数据时,其他事务也能读,但不能修改。如果在修改数据,其他事务则不能读取。

Sets a shared mode lock on any rows that are read. Other sessions can read the rows, but cannot modify them until your transaction commits. If any of these rows were changed by another transaction that has not yet committed, your query waits until that transaction ends and then uses the latest values.

2. SELECT ... FOR UPDATE

锁定所有相关实体,如同对这些实体提交UPDATE,其他事务从读取数据就开始被阻塞。

For index records the search encounters, locks the rows and any associated index entries, the same as if you issued an UPDATE statement for those rows. Other transactions are blocked from updating those rows, from doing SELECT ... LOCK IN SHARE MODE, or from reading the data in certain transaction isolation levels. Consistent reads ignore any locks set on the records that exist in the read view. (Old versions of a record cannot be locked; they are reconstructed by applying undo logs on an in-memory copy of the record.)

 

用第二种方式进行行锁比较好。


2018年5月11号续

  在使用数据库行锁的时候,需要注意,查询条件必须是索引(index),for update才能够生效。可以从查询范围看,for update是否生效。通过EXPLAN查看查询语句的执行计划,其中涉及的字段及其含义(参考EXPLAIN Output Columns):

ColumnJSON NameMeaning
id select_id The SELECT identifier   SELECT标识符
select_type None The SELECT type    查询类型(常见的SIMPLE)
table table_name The table for the output row    涉及的数据表
partitions partitions The matching partitions     
type access_type The join type   访问类型,如const、ref
possible_keys possible_keys The possible indexes to choose   可选的索引
key key The index actually chosen    实际使用的索引
key_len key_length The length of the chosen key  索引长度
ref ref The columns compared to the index  与索引相关的列
rows rows Estimate of rows to be examined   查询需要检查的行数
filtered filtered Percentage of rows filtered by table condition  根据条件过滤百分比,即最终结果数与rows的百分比
Extra None Additional information   其他信息

   其中比较关键的是type、possible_keys、key,其中,如果根据查询条件没有可以使用的索引,执行计划会遍历全表,对整个数据表加锁。

  访问类型(type)是SQL查询优化的关键指标,查询值由好到坏 :system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL,具体可参照EXPLAIN Join TypesMySQL高级 之 explain执行计划详解,其中常见的有const、eq_ref、ref、range和ALL。

const:数据表中只有一条数据匹配查询条件,如按主键或唯一索引扫描。

eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键 或 唯一索引扫描,多用于2个以上的表联合查询。

ref:非唯一性索引扫描,返回所有匹配的结果。

range:只检索指定范围内的行,并根据索引选择匹配的,一般WHERE语句中出现 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN,或 IN()。

ALL:全表扫描,最低效的方式。

(1)在Navicat中执行以下SQL:

EXPLAIN Select * from fi_doctype_ts WHERE id='130' for update

输出结果:

 

该执行计划:查询方式为SIMPLE(单表简单查询)、type为const、possible_keys和key为主键、索引长度为146、需要检索的行数为1、过滤百分比为100%。

(2)无索引查询:

EXPLAIN Select * from fi_doctype WHERE column1='111' and column2='2222';

执行计划:查询方式为SIMPLE(单表简单查询)、type为ALL、possible_keys和key为Null、需要检索的行数为20、过滤百分比为5%,即从20条中查出1条。

(3)添加索引后(添加唯一索引时type应为eq_ref,下边添加非唯一索引):

ALTER TABLE fi_doctype ADD INDEX(column1,column2);
EXPLAIN Select * from fi_doctype WHERE column1='111' and column2='222';

  

执行计划:查询方式为SIMPLE(单表简单查询)、type为ref、possible_keys和key为column1、需要检索的行数为1、过滤百分比为100%。

 索引查询优化可参考官方文档:Tutorial: Using Explain to Improve Query Performance

通过添加索引,在sql中添加for update才得以生效,不然会锁定整个表

 

posted @ 2018-04-04 11:10  水木竹水  阅读(975)  评论(0编辑  收藏  举报