标签:AC space table warnings prim tran nod bee lte
root@slave01 22:28: [sqltest]> create table user_info (id int primary key,username varchar(20), status tinyint,key(username));
Query OK, 0 rows affected (0.03 sec)
#
root@slave01 22:54: [sqltest]> show create table user_info;
+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user_info | CREATE TABLE `user_info` (
`id` int(11) NOT NULL,
`username` varchar(20) DEFAULT NULL,
`status` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
#
insert into user_info values(1,‘yzw1‘,1);
insert into user_info values(3,‘yzw3‘,0);
insert into user_info values(5,‘yzw5‘,1);
root@master 23:15: [sqltest]> desc update user_info set status=1 where username=‘yzw3‘;
+----+-------------+-----------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+
| 1 | UPDATE | user_info | NULL | range | username | username | 63 | const | 1 | 100.00 | Using where |
+----+-------------+-----------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+
1 row in set (0.01 sec)
#
root@master 23:15: [sqltest]> desc update user_info set username=‘yzw33‘ where id=3;
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| 1 | UPDATE | user_info | NULL | range | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using where |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
1 row in set (0.00 sec)
session 1 | session 2 |
---|---|
begin; update user_info set status=1 where username=‘yzw3‘; |
|
此时session除了给索引username加x锁,还给主键索引id=3的行记录加了x锁,但是这两个锁并不是同时获取的 | |
第一步先获取普通索引username上的X锁 | |
此时session 2进行更新 | begin; update user_info set username=‘yzw33‘ where id=3; |
session 2 第一步需要先获取聚簇索引,也就是主键索引上的X锁 第二步需要获取普通索引username上的X锁 |
|
出现死锁ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction | |
需要session 2的主键索引X锁 | 需要session 1的普通索引username X锁 |
root@master 23:11: [(none)]> select * from information_schema.innodb_locks;
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
| 48736590:1135:3:3 | 48736590 | X | RECORD | `sqltest`.`user_info` | PRIMARY | 1135 | 3 | 3 | 3 |
| 48733648:1135:3:3 | 48733648 | X | RECORD | `sqltest`.`user_info` | PRIMARY | 1135 | 3 | 3 | 3 |
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)
1.给status列增加索引
create index idx_status on user_info(status);
2.执行计划,两条语句都是走的普通索引
root@master 23:26: [sqltest]> desc update user_info set status=1 where username=‘yzw3‘;
+----+-------------+-----------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+
| 1 | UPDATE | user_info | NULL | range | username | username | 63 | const | 1 | 100.00 | Using where |
+----+-------------+-----------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+
1 row in set (0.04 sec)
#
root@master 23:29: [sqltest]> desc update user_info set username=‘yzw33‘ where status=0;
+----+-------------+-----------+------------+-------+---------------+------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+------------+---------+-------+------+----------+-------------+
| 1 | UPDATE | user_info | NULL | range | idx_status | idx_status | 2 | const | 1 | 100.00 | Using where |
+----+-------------+-----------+------------+-------+---------------+------------+---------+-------+------+----------+-------------+
1 row in set (0.01 sec)
3.两个会话更新索引
session 1 | session 2 |
---|---|
begin; update user_info set status=1 where username=‘yzw3‘; |
|
第一步已经获取了username的普通索引X锁 | begin; update user_info set username=‘yzw33‘ where status=0; |
第一步已经获取status的普通索引X锁 第二步给主键索引加X锁 |
|
第二步需要给主键索引加X锁,无法获取 | 出现死锁ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
因为要更新非主键索引username,因此要给username加X锁,但是无法获取 |
root@master 23:30: [sqltest]> select * from information_schema.innodb_locks;
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
| 48739611:1135:5:2 | 48739611 | X | RECORD | `sqltest`.`user_info` | idx_status | 1135 | 5 | 2 | 0, 3 |
| 48738737:1135:5:2 | 48738737 | X | RECORD | `sqltest`.`user_info` | idx_status | 1135 | 5 | 2 | 0, 3 |
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)
begin;
update user_info set status=1 where id in (select id from (select id from user_info where username=‘yzw3‘) t);
begin;
update user_info set username=‘yzw33‘ where id in (select id from (select id from user_info where status=0) t);
root@master 23:56: [sqltest]> select * from information_schema.innodb_locks;
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
| 48744368:1135:3:3 | 48744368 | X | RECORD | `sqltest`.`user_info` | PRIMARY | 1135 | 3 | 3 | 3 |
| 48744353:1135:3:3 | 48744353 | X | RECORD | `sqltest`.`user_info` | PRIMARY | 1135 | 3 | 3 | 3 |
+-------------------+-------------+-----------+-----------+-----------------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)
依然存在死锁,因为都给主键id加了X锁
1.构造数据
create table user_info1 (id int primary key,name varchar(10), level tinyint);
insert into user_info1 values(1,‘AA‘,0);
insert into user_info1 values(3,‘CC‘,0);
insert into user_info1 values(5,‘EE‘,2);
insert into user_info1 values(7,‘GG‘,5);
insert into user_info1 values(9,‘GG‘,7);
insert into user_info1 values(11,‘JJ‘,20);
session 1 >select * from user_info1;
+----+------+-------+
| id | name | level |
+----+------+-------+
| 1 | AA | 0 |
| 3 | CC | 0 |
| 5 | EE | 2 |
| 7 | GG | 5 |
| 9 | GG | 7 |
| 11 | JJ | 20 |
+----+------+-------+
6 rows in set (0.00 sec)
2.过程
session 1 | session 2 |
---|---|
begin; insert into user_info1 values(2,‘BB‘,1); |
|
delete from user_info1 where name=‘BB‘; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
此时是RC级别 session 2首先插入数据并给这一行加X锁,因为没有索引,同时在两边加gap锁 |
delete from user_info1 where name=‘BC‘; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
|
delete from user_info1 where level=8; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
|
delete where条件没有索引,会对整表扫描并加gap锁,但是此时session2已经加了gap锁,session1的delete事务被回退 |
delete from user_info1 where name=‘BB‘
------- TRX HAS BEEN WAITING 10 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1137 page no 3 n bits 80 index PRIMARY of table `sqltest`.`user_info1` trx id 48906774 lock_mode X locks rec but not gap waiting
Record lock, heap no 8 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
3保持RCset tx_isolation=‘READ-COMMITTED‘;
级别,增加索引
session 1 >create index idx_name_level on user_info1(name,level);
Query OK, 0 rows affected (0.12 sec)
Records: 0 Duplicates: 0 Warnings: 0
session 1 | session 2 |
---|---|
begin; insert into user_info1 values(2,‘BB‘,1); |
|
delete from user_info1 where name=‘BB‘; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
此时是RC级别 session 2首先插入数据并加gap锁, |
session 1 >delete from user_info1 where name=‘BC‘; Query OK, 0 rows affected (0.00 sec) |
RC级别下,增加了索引,没有了gap锁 |
session 1 >delete from user_info1 where name=‘BB‘; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction session 1 >delete from user_info1 where level=8; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction session 1 >delete from user_info1 where level=20; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction session 1 >delete from user_info1 where level=7; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction session 1 >delete from user_info1 where level=2; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
索引(a,b),如果where字段使用了索引a,则不存在gap锁了,猜测是单独使用索引b还是会存在gap锁,因为无法使用索引 |
root@master 16:31: [(none)]> select * from information_schema.innodb_locks;
+-------------------+-------------+-----------+-----------+------------------------+------------+------------+-----------+----------+-----------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+------------------------+------------+------------+-----------+----------+-----------+
| 48942672:1137:3:8 | 48942672 | X | RECORD | `sqltest`.`user_info1` | PRIMARY | 1137 | 3 | 8 | 2 |
| 48942589:1137:3:8 | 48942589 | S | RECORD | `sqltest`.`user_info1` | PRIMARY | 1137 | 3 | 8 | 2 |
+-------------------+-------------+-----------+-----------+------------------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)
4增加索引(b),验证
session 1 >create index idx_level on user_info1(level);
Query OK, 0 rows affected (0.08 sec)
Records: 0 Duplicates: 0 Warnings: 0
session 1 | session 2 |
---|---|
begin; insert into user_info1 values(2,‘BB‘,1); |
|
delete from user_info1 where name=‘BB‘; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
此时是RC级别 session 2首先插入数据并加X锁 |
session 1 >delete from user_info1 where name=‘BC‘; Query OK, 0 rows affected (0.00 sec) session 1 >delete from user_info1 where name=‘BB‘; ERROR 1205 (HY000): Lock wait timeout xceeded; try restarting transaction session 1 >delete from user_info1 where level=8; Query OK, 0 rows affected (0.01 sec) session 1 >delete from user_info1 where level=20; Query OK, 1 row affected (0.01 sec) session 1 >delete from user_info1 where level=7; Query OK, 1 row affected (0.00 sec) session 1 >delete from user_info1 where level=2; Query OK, 1 row affected (0.00 sec) |
此时b有了索引,RC级别下也就不存在gap锁了 |
5更改为RR级别set tx_isolation=‘REPEATABLE-READ‘;
,先使用索引(a,b)
session 2 >drop index idx_level on user_info1;
Query OK, 0 rows affected (0.16 sec)
Records: 0 Duplicates: 0 Warnings: 0
session 2 >begin;
Query OK, 0 rows affected (0.00 sec)
#
session 2 >insert into user_info1 values(2,‘BB‘,1);
Query OK, 1 row affected (0.00 sec)
#
session 1 >delete from user_info1 where name=‘BB‘;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session 1 >delete from user_info1 where name=‘BC‘;
Query OK, 0 rows affected (0.00 sec)
#
session 1 >delete from user_info1 where level=8;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session 1 >delete from user_info1 where level=2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session 1 >delete from user_info1 where name=‘CB‘;
Query OK, 0 rows affected (0.00 sec)
#
session 1 >delete from user_info1 where name=‘BA‘;
Query OK, 0 rows affected (0.00 sec)
6总结
1) RC和RR级别下如果更新没有索引的字段,会加gap锁
2) 必须能用上索引,(a,b)只用b是无效索引
3) RC增加了索引后就不存在gap锁了
3) RR级别在没有索引的情况,用不上索引也会产生gap锁
4) 解决方法,最好使用RC级别+索引,或者RR下修改参数innodb_locks_unsafe_for_binlog=on
5) 间隙锁只会block住insert操作
session 1 >select * from user_info1;
+----+------+-------+
| id | name | level |
+----+------+-------+
| 1 | AA | 0 |
| 3 | BA | 1 |
| 5 | EE | 2 |
| 7 | GG | 5 |
| 9 | GG | 7 |
| 11 | JJ | 20 |
+----+------+-------+
6 rows in set (0.00 sec)
#
session 1 >begin;
Query OK, 0 rows affected (0.00 sec)
#
session 1 >update user_info1 set level=3 where name=‘BA‘;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
session 2 >begin;
Query OK, 0 rows affected (0.01 sec)
#
session 2 >insert into user_info1 values(2,‘AB‘,1);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
create table t3 (id int auto_increment,coupon_id int,uid int,is_inuse tinyint,primary key(id),key (coupon_id,uid));
insert into t3 (coupon_id,uid,is_inuse) values(16,160825,1);
insert into t3 (coupon_id,uid,is_inuse) values(16,160835,1);
insert into t3 (coupon_id,uid,is_inuse) values(16,160845,1);
insert into t3 (coupon_id,uid,is_inuse) values(16,160855,1);
insert into t3 (coupon_id,uid,is_inuse) values(16,160865,1);
root@master 22:56: [sqltest]> select * from t3;
+----+-----------+--------+----------+
| id | coupon_id | uid | is_inuse |
+----+-----------+--------+----------+
| 1 | 16 | 160825 | 1 |
| 2 | 16 | 160835 | 1 |
| 3 | 16 | 160845 | 1 |
| 4 | 16 | 160855 | 1 |
| 5 | 16 | 160865 | 1 |
+----+-----------+--------+----------+
5 rows in set (0.00 sec)
1.session 1给id=3的行记录加X锁,同时加间隙锁:160835~160845,160845~160855
set tx_isolation=‘REPEATABLE-READ‘;
set autocommit=0;
start transaction;
select * from t3 where (uid=160845 and coupon_id=16 and is_inuse=1) for update;
+----+-----------+--------+----------+
| id | coupon_id | uid | is_inuse |
+----+-----------+--------+----------+
| 3 | 16 | 160845 | 1 |
+----+-----------+--------+----------+
1 row in set (0.00 sec)
2.session 2插入记录,在间隙范围:160835~160845
set tx_isolation=‘REPEATABLE-READ‘;
set autocommit=0;
start transaction;
insert into t3 (coupon_id,uid,is_inuse) values (16,160840,1);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
3.lock
root@master 23:08: [sqltest]> select * from information_schema.innodb_locks;
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
| 49020303:1139:4:4 | 49020303 | X,GAP | RECORD | `sqltest`.`t3` | coupon_id | 1139 | 4 | 4 | 16, 160845, 3 |
| 49020011:1139:4:4 | 49020011 | X | RECORD | `sqltest`.`t3` | coupon_id | 1139 | 4 | 4 | 16, 160845, 3 |
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
2 rows in set, 1 warning (0.00 sec)
4.session 2插入记录,在间隙范围:160845~160855
set tx_isolation=‘REPEATABLE-READ‘;
set autocommit=0;
start transaction;
insert into t3 (coupon_id,uid,is_inuse) values (16,160850,1);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
5.lock
root@master 23:11: [sqltest]> select * from information_schema.innodb_locks;
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
| 49022356:1139:4:5 | 49022356 | X,GAP | RECORD | `sqltest`.`t3` | coupon_id | 1139 | 4 | 5 | 16, 160855, 4 |
| 49020011:1139:4:5 | 49020011 | X,GAP | RECORD | `sqltest`.`t3` | coupon_id | 1139 | 4 | 5 | 16, 160855, 4 |
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
2 rows in set, 1 warning (0.00 sec)
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session 2 >insert into t3 (coupon_id,uid,is_inuse) values (16,160860,1);
Query OK, 1 row affected (0.01 sec)
1.数据
session 1 >select * from t3;
+----+-----------+--------+----------+
| id | coupon_id | uid | is_inuse |
+----+-----------+--------+----------+
| 1 | 16 | 160825 | 1 |
| 2 | 16 | 160835 | 1 |
| 3 | 16 | 160845 | 1 |
| 4 | 16 | 160855 | 1 |
| 5 | 16 | 160865 | 1 |
+----+-----------+--------+----------+
5 rows in set (0.00 sec)
2.update一条不存在的记录,此时gap锁范围:160835~160845,160845~160855
set tx_isolation=‘REPEATABLE-READ‘;
set autocommit=0;
start transaction;
update t3 set is_inuse=0 where coupon_id=16 and uid=160845 and is_inuse=1;
3.在间隙范围插入新值会产生死锁
set tx_isolation=‘REPEATABLE-READ‘;
set autocommit=0;
start transaction;
insert into t3 (coupon_id,uid,is_inuse) values (16,160840,1);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
4.lock
root@master 23:11: [sqltest]> select * from information_schema.innodb_locks;
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
| 49023844:1139:4:4 | 49023844 | X,GAP | RECORD | `sqltest`.`t3` | coupon_id | 1139 | 4 | 4 | 16, 160845, 3 |
| 49023813:1139:4:4 | 49023813 | X | RECORD | `sqltest`.`t3` | coupon_id | 1139 | 4 | 4 | 16, 160845, 3 |
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+---------------+
2 rows in set, 1 warning (0.00 sec)
1.删除索引
session 2 >drop index coupon_id on t3;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
#
session 2 >commit;
Query OK, 0 rows affected (0.00 sec)
2.事务1加锁
set tx_isolation=‘REPEATABLE-READ‘;
set autocommit=0;
start transaction;
select * from t3 where (uid=160845 and coupon_id=16 and is_inuse=1) for update;
3.事务2在间隙锁范围外插入,此时不是间隙锁,而是全表锁,无法插入
set tx_isolation=‘REPEATABLE-READ‘;
set autocommit=0;
start transaction;
select * from t3 where (uid=160850 and coupon_id=16 and is_inuse=1) for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
4.lock
root@master 23:27: [sqltest]> select * from information_schema.innodb_locks;
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
| 49025074:1139:3:2 | 49025074 | X | RECORD | `sqltest`.`t3` | PRIMARY | 1139 | 3 | 2 | 1 |
| 49025016:1139:3:2 | 49025016 | X | RECORD | `sqltest`.`t3` | PRIMARY | 1139 | 3 | 2 | 1 |
+-------------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)
标签:AC space table warnings prim tran nod bee lte
原文地址:https://www.cnblogs.com/jenvid/p/9074780.html