Mysql 锁学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xxzhaobb/article/details/84029216

1 读锁,简称S锁 ,一个事务获取了一个数据行的读锁,其他事务能获取该行对应的读锁,但是不能获取写锁。

2 写锁,简称X锁, 一个事务获取了一个数据行的写锁,其他事务就不能再获取该行的其他所,写锁优先级最高。
3 MDL锁, mysql5.5开始引入了meta data lock.简称MDL锁,用于保证表中元数据的信息。在会话1中表开启了事务查询后,会自动获取一个MDL锁,会话2就不可以执行任何的DDL语句的操作。

-- 会话1

mysql> select * from t1;
+------+-------+------+
| year | month | day  |
+------+-------+------+
| 2000 |    01 |   01 |
| 2000 |    01 |   20 |
| 2000 |    01 |   30 |
| 2000 |    02 |   02 |
| 2000 |    02 |   23 |
| 2000 |    02 |   23 |
| 2018 |    10 |   28 |
| 2018 |    11 |   05 |
| 2018 |    11 |   04 |
| 2018 |    11 |   03 |
| 2018 |    11 |   06 |
| 2018 |    11 |   07 |
| 2018 |    11 |   08 |
| 2018 |    11 |   09 |
| 2018 |    11 |   10 |
+------+-------+------+
15 rows in set (0.00 sec)

mysql>

-- 会话2 ,一直卡在这里

mysql> alter table t1 add column other varchar(100);

-- 查看processlist ,发现有lock

mysql> show full processlist;
+----+------+-----------------+------+-------------+------+-----------------------------------------------------------------------+----------------------------------+
| Id | User | Host            | db   | Command     | Time | State                                                                 | Info                             |
+----+------+-----------------+------+-------------+------+-----------------------------------------------------------------------+----------------------------------+
|  1 | root | localhost       | test | Sleep       |   65 |                                                                       | NULL                             |
|  2 | root | localhost       | test | Query       |   45 | Waiting for table metadata lock                                       | alter table t1 drop column other |
|  3 | rep1 | localhost:27591 | NULL | Binlog Dump | 4555 | Master has sent all binlog to slave; waiting for binlog to be updated | NULL                             |
|  4 | root | localhost       | test | Query       |    0 | init                                                                  | show full processlist            |
+----+------+-----------------+------+-------------+------+-----------------------------------------------------------------------+----------------------------------+
4 rows in set (0.00 sec)

mysql>

-- 会话1 rollback后,会话2 立刻执行

 mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql>

mysql> alter table t1 add column other varchar(100);
Query OK, 0 rows affected (10 min 59.28 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql>

4 意向锁
-- 在innodb中,意向锁是表级锁,分为意向共享锁,意向排他锁。。(对行加锁前,先取得表的锁?? )

-- 意向共享锁: IS , 在给一个数据行加共享锁前,必须先取得该表的IS锁。
-- 意向排他锁: IX, 在给一个数据行加排他锁前,必须先取得该表的IX锁。

5 innodb 行锁种类
5.1 单个行记录的锁(record lock)
5.2 间隙锁(gap lock)
5.3 记录锁和间隙锁的组合叫做next-key lock .

-- 单个行记录的锁 ,更新同一行数据的时候,会出现锁等待的现象
-- 会话1

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set year=2001 where day=10;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql>

--会话2

扫描二维码关注公众号,回复: 4090188 查看本文章
mysql> update t1 set year=2000 where day=10;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

--  再测试,更新不同的列,其中表上没有索引 ,其中只有一个会话可以更新,一个会话报错,
-- 会话1 更新day=10的year

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update t1 set year=2001 where day=10;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

-- 会话2 ,更新day=05的year

mysql> update t1 set year=2002 where day=05;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

原因: 没有索引的时候,会话1更新的时候,所有的行上都加了锁。innodb的行锁,实际是加在索引项上面的。
如果day上有索引,更新的时候就不会出现问题

-- 加上索引,再更新,发现两个会话都可以更新

create index idx_day on t1(day);
update t1 set year=2001 where day=10;
update t1 set year=2002 where day=05;

-- 会话1 ,可以更新

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set year=2001 where day=10;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql>

-- 会话2 也可以更新

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set year=2002 where day=05;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql>

-- 备注,Oracle下不存在这个问题 。但是oracle的主外键可能会存在这个问题 。主外键就不演示了

APPS@test>select * from t1;

      YEAR      MONTH        DAY
---------- ---------- ----------
      2001          1          1
      2001          1          2
      2001          1          3
      2001          1          4
      2001          1          5
      2001          1          5
      2001          1          6

7 rows selected.

APPS@test>update t1 set year=2002 where day=2;

1 row updated.

APPS@test>


APPS@test>select * from t1;

      YEAR      MONTH        DAY
---------- ---------- ----------
      2001          1          1
      2001          1          2
      2001          1          3
      2001          1          4
      2001          1          5
      2001          1          5
      2001          1          6

7 rows selected.

APPS@test>update t1 set year=2003 where day=5;

2 rows updated.

APPS@test>

-- 间隙锁
间隙锁,只锁定行记录数据的范围,不包含记录本身,即不允许在此范围内插入任何数据 。

show variables like '%iso%'; -- 在RR隔离级别下
-- 会话1 ,在t1表中查询day<20的记录

select * from t1 where day<20 lock in share mode;

-- 会话2 ,在t1表中插入day=18的记录

insert into t1 values(2017,10,18);

mysql> show variables like '%iso%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where day<20 lock in share mode;
+------+-------+------+
| year | month | day  |
+------+-------+------+
| 2000 |    01 |   01 |
| 2000 |    02 |   02 |
| 2018 |    11 |   05 |
| 2018 |    11 |   04 |
| 2018 |    11 |   03 |
| 2018 |    11 |   06 |
| 2018 |    11 |   07 |
| 2018 |    11 |   08 |
| 2018 |    11 |   09 |
| 2018 |    11 |   10 |
+------+-------+------+
10 rows in set (0.00 sec)

mysql>

mysql> insert into t1 values(2017,10,18);   
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

-- 换成RC隔离,再次测试 ,是可以进行操作的 。结论,RC隔离模式下,是允许出现幻读现象的

mysql> show variables like '%iso%';
+---------------+----------------+
| Variable_name | Value          |
+---------------+----------------+
| tx_isolation  | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec)

mysql>

-- 会话1 ,在t1表中查询day<20的记录

select * from t1 where day<20 lock in share mode;

-- 会话2 ,在t1表中插入day=18的记录

insert into t1 values(2017,10,18);

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1 where day<20 lock in share mode;
+------+-------+------+
| year | month | day  |
+------+-------+------+
| 2000 |    01 |   01 |
| 2000 |    02 |   02 |
| 2018 |    11 |   05 |
| 2018 |    11 |   04 |
| 2018 |    11 |   03 |
| 2018 |    11 |   06 |
| 2018 |    11 |   07 |
| 2018 |    11 |   08 |
| 2018 |    11 |   09 |
| 2018 |    11 |   10 |
+------+-------+------+
10 rows in set (0.00 sec)

mysql>

mysql> insert into t1 values(2017,10,18);
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    3
Current database: test

Query OK, 1 row affected (0.02 sec)

mysql>

Next-key locks ,隔离方式要在 RR下
是记录锁与间隙锁的组合,当innodb扫描记录的时候,会先对选中的索引记录加上记录锁,再对索引记录两边的间隙上加上间隙锁 。

-- 会话1

select * from t1 where day<20 for update;

-- 会话2 ,插入day=20的记录,发现无法插入成功,出现了锁超时 。说明不光锁了day<20这个范围,还包含day=20 。

insert into t1 values(2017,10,20);


mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1 where day<20 for update;
+------+-------+------+
| year | month | day  |
+------+-------+------+
| 2000 |    01 |   01 |
| 2000 |    02 |   02 |
| 2018 |    11 |   05 |
| 2018 |    11 |   04 |
| 2018 |    11 |   03 |
| 2018 |    11 |   06 |
| 2018 |    11 |   07 |
| 2018 |    11 |   08 |
| 2018 |    11 |   09 |
| 2018 |    11 |   10 |
| 2017 |    10 |   18 |
+------+-------+------+
11 rows in set (0.00 sec)

mysql>

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1 values(2017,10,20);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

----------- 锁等待和死锁 ,和Oracle类似
--检查方法,主要查询这几个表 

select * from innodb_trx
select * from INNODB_LOCK_WAITS
select * from INNODB_LOCKS

END

猜你喜欢

转载自blog.csdn.net/xxzhaobb/article/details/84029216