时间:2021-07-01 10:21:17 帮助过:5人阅读
lock 主要是事务,数据库逻辑内容,事务过程 latch/mutex 内存底层锁; 更新丢失
事务锁粒度
mysql> show status like ‘%innodb_row_lock%‘; +-------------------------------+-------+ | Variable_name | Value | +-------------------------------+-------+ | Innodb_row_lock_current_waits | 0 | | Innodb_row_lock_time | 0 | | Innodb_row_lock_time_avg | 0 | | Innodb_row_lock_time_max | 0 | | Innodb_row_lock_waits | 0 | +-------------------------------+-------+ 5 rows in set (0.00 sec)如果发现锁争用比较严重,如innodb_row_lock_waits 和 innodb_row_lock_time_avg的值比较高, 还可以通过设置innodb monitor 来进一步观察发生锁冲突的表,数据行等,并分析锁争用的原因: innodb锁模式与粒度
数据库加锁操作 一般的select语句不加任何锁,也不会被任何事物锁阻塞 读的隔离性由MVCC确保 undo log 用来帮助事务回滚及MVCC(多版本并发控制 ,即select时可以使用行数据的快照,而不用等待锁资源) S锁 手动:select * from tb_test lock in share mode; 自动:insert前 X锁 手动:
select * from tb_test for update;
自动:update,delete 前
线上环境中: 锁等待时间:innodb_lock_wait_timeoutmysql>show global variables like "%wait%"innodb 行锁
mysql> show create table t2\G; *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 mysql> select * from t2; +------+------+ | a | b | +------+------+ | 1 | 2 | | 1 | 3 | +------+------+ 此时A连接 在b =2 时加 写锁; mysql> select * from t2 where b =2 for update; +------+------+ | a | b | +------+------+ | 1 | 2 | +------+------+ 而此时再B连接中再对b=3,加写锁时,失败; mysql> select * from t2 where b=3 for update; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction说明,表中没有索引时,innodb将对整个表加锁,而不能体现行锁的特性; b) 索引上有重复值,可能锁住多个记录
mysql> show create table t2\G; *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, KEY `a` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) mysql> select * from t2; +------+------+ | a | b | +------+------+ | 1 | 2 | | 1 | 3 | | 2 | 9 | +------+------+ 在A连接中,在a=1,b=2处加一个写锁;实际上 是在a=1这个索引上加的锁 mysql> select * from t2 where a=1 and b=2 for update; +------+------+ | a | b | +------+------+ | 1 | 2 | +------+------+ 1 row in set (0.00 sec) 在B连接中,在a=1 and b=3处加写锁失败,因都是a=1这个索引,而A中已经对a=1这个索引的行加过了锁; mysql> select * from t2 where a =1 and b=3 for update; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 此时B连接是可以对 a=2 and b =9 这一行中,在a=2 这个索引上加锁的; mysql> select * from t2 where a=2 and b =9 for update ; +------+------+ | a | b | +------+------+ | 2 | 9 | +------+------+注意 行锁升级成表锁:
mysql> select * from t2 where b =9 for update ;这句对本意在b=9这行加索引,b又没有加索引,所以这是对整个表加锁;因为没有指定a =2,所以mysql找不到a这个索引的; c) 查询有多个索引可以走,可以对不同索引加锁
mysql> show create table t2\G; *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, KEY `a` (`a`), KEY `b` (`b`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 mysql> select * from t2; +------+------+ | a | b | +------+------+ | 1 | 2 | | 1 | 3 | | 2 | 9 | +------+------+ 在A连接中对 a=1 and b=2 加锁; mysql> select * from t2 where a =1 and b =2 for update; +------+------+ | a | b | +------+------+ | 1 | 2 | +------+------+ 此时B连接中对a =1 and b=3 ,也是可以加锁的;这是因为mysql 可以从a=1这个索引来加锁,也可以对b=3加锁; 所以就与上面b)中只能对a=1索引来加锁 区别开来; mysql> select * from t2 where a =1 and b =3 for update; +------+------+ | a | b | +------+------+ | 1 | 3 | +------+------+
innodb的gap lock 间隙锁 gap lock消灭幻读 innodb消灭幻读仅仅为了确保 statement模式replicate的主从一致性 小心gap lock 自增主键做条件更新,性能最好; gap lock 间隙锁 解释:
mysql> select * from t2; +------+------+ | a | b | +------+------+ | 20 | 2 | | 24 | 4 | | 27 | 5 | | 27 | 6 | | 27 | 8 | | 30 | 6 | | 31 | 4 | | 32 | 9 | +------+------+ 8 rows in set (0.00 sec) 在A连接中给a=27 加锁(a 是有索引的) mysql> select * from t2 where a=27 for update; +------+------+ | a | b | +------+------+ | 27 | 5 | | 27 | 6 | | 27 | 8 | +------+------+ 3 rows in set (0.00 sec)此时隔离等级是Repeatable Read,标准的是可以出现幻读现象的, 即在B连接中 insert into t2 values(27,3),是可以插入成功的,而且B连接提交后,A连接是可以查看到增加的,27,3这一行的。 而innodb 通过间隙锁是的B连接中 insert into t2 values(27,3) 插入失败,来消灭幻读的出现。 但是这种方法是有局限的,它会将a=24--29(30-1)中间的任何数都锁住,所以才叫间隙锁; B连接中则只能插入不在这个区间的数据; 锁升级
死锁
死锁数据库自动解决 数据库挑选冲突事务中回滚代价较小的事务回滚 死锁预防 单表死锁可以根据批量更新表的更新条件排序 可能冲突的跨表事务尽量避免并发 尽量缩短事务长度 排查死锁:
innodb事务锁
标签: