行锁包括了共享锁、排他锁、间隙锁、记录锁、临键锁.
共享锁是指,一个事务中如果开启了共享锁,其它事务也可以共享这个锁、所谓的共享就是指所有的线程、connection、会话、事务等都可以获得这个锁,都可以读取到加了共享锁的数据,但是,不能修改数据。除非开启共享锁的事务结束,其它事务才能修改数据。
排他锁是指,一个事务中如果对指定的数据记录开启了排他锁,则其它事务无法再获得该数据的共享锁,也无法获得该数据的排他锁,即无法读也无法修改,除非开启排他锁的事务结束。但是请注意:执行普通的select查询语句照样可以执行,可以从快照中拿到数据,这是由于Mysql的默认隔离级别为Repeatable read决定的。
执行命令 show status like 'innodb_row_lock%'
通过检查InnoDB_row_lock 状态变量分析系统上的行锁的争夺情况 show status like 'innodb_row_lock%'
innodb_row_lock_current_waits
: 当前正在等待锁定的数量
innodb_row_lock_time
: 从系统启动到现在锁定总时间长度;非常重要的参数,
innodb_row_lock_time_avg
: 每次等待所花平均时间;非常重要的参数,
innodb_row_lock_time_max
: 从系统启动到现在等待最常的一次所花的时间;
innodb_row_lock_waits
: 系统启动后到现在总共等待的次数;非常重要的参数。直接决定优化的方向和策略。
行锁优化
1 尽可能让所有数据检索都通过索引来完成,避免无索引行或索引失效导致行锁升级为表锁。
2 尽可能避免间隙锁带来的性能下降,减少或使用合理的检索范围。
3 尽可能减少事务的粒度,比如控制事务大小,而从减少锁定资源量和时间长度,从而减少锁的竞争等,提供性能。
4 尽可能低级别事务隔离,隔离级别越高,并发的处理能力越低。
事务的隔离级别
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大。这是因为事务隔离实质上是将事务在一定程度上"串行"进行,这显然与"并发"是矛盾的。根据自己的业务逻辑,权衡能接受的最大副作用。从而平衡了"隔离" 和 "并发"的问题。MySQL默认隔离级别是可重复读。
脏读,不可重复读,幻读,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。
+------------------------------+---------------------+--------------+--------------+--------------+
| 隔离级别 | 读数据一致性 | 脏读 | 不可重复 读 | 幻读 |
+------------------------------+---------------------+--------------+--------------+--------------+
| 未提交读(Read uncommitted) | 最低级别 | 是 | 是 | 是 |
+------------------------------+---------------------+--------------+--------------+--------------+
| 已提交读(Read committed) | 语句级 | 否 | 是 | 是 |
+------------------------------+---------------------+--------------+--------------+--------------+
| 可重复读(Repeatable read) | 事务级 | 否 | 否 | 是 |
+------------------------------+---------------------+--------------+--------------+--------------+
| 可序列化(Serializable) | 最高级别,事务级 | 否 | 否 | 否 |
+------------------------------+---------------------+--------------+--------------+--------------+
查看当前数据库的事务隔离级别:show variables like 'tx_isolation';
mysql> show variables like 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
使用行锁,注意事项
- InnoDB 支持表锁和行锁,使用索引作为检索条件修改数据时采用行锁,否则采用表锁。
- InnoDB 自动给修改操作加锁,给查询操作不自动加锁
- 行锁可能因为未使用索引而升级为表锁,所以除了检查索引是否创建的同时,也需要通过explain执行计划查询索引是否被实际使用。
- 行锁相对于表锁来说,优势在于高并发场景下表现更突出,毕竟锁的粒度小。
- 当表的大部分数据需要被修改,或者是多表复杂关联查询时,建议使用表锁优于行锁。
- 为了保证数据的一致完整性,任何一个数据库都存在锁定机制。锁定机制的优劣直接影响到一个数据库的并发处理能力和性能。