请求锁模式
是否兼容
当前锁模式 |
None |
读锁 |
写锁 |
读锁 |
是 |
是 |
否 |
写锁 |
是 |
否 |
否 |
session_1 |
session_2 |
获得表film_text的WRITE锁定
mysql> lock table film_text write;
Query OK, 0 rows affected (0.00 sec) |
|
当前session对锁定表的查询、更新、插入操作都可以执行:
mysql> select film_id,title from film_text where
film_id = 1001;
+---------+-------------+
| film_id | title
|
+---------+-------------+
| 1001 | Update Test |
+---------+-------------+
1 row in set (0.00 sec)
mysql> insert into film_text (film_id,title)
values(1003,‘Test‘);
Query OK, 1 row affected (0.00 sec)
mysql> update film_text set title = ‘Test‘ where
film_id = 1001;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings:
0 |
其他session对锁定表的查询被阻塞,需要等待锁被释放:
mysql> select film_id,title from film_text where
film_id = 1001;
等待 |
释放锁:
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec) |
等待 |
Session2获得锁,查询返回:
mysql> select film_id,title from film_text where
film_id = 1001;
+---------+-------+
| film_id | title |
+---------+-------+
| 1001 | Test |
+---------+-------+
1 row in set (57.59 sec) |
session_1 |
session_2 |
获得表film_text的READ锁定
mysql> lock table film_text read;
Query OK, 0 rows affected (0.00 sec) |
|
当前session可以查询该表记录
mysql> select film_id,title from film_text where
film_id = 1001;
+---------+------------------+
| film_id |
title
|
+---------+------------------+
| 1001 | ACADEMY DINOSAUR |
+---------+------------------+
1 row in set (0.00 sec) |
其他session也可以查询该表的记录
mysql> select film_id,title from film_text where
film_id = 1001;
+---------+------------------+
| film_id |
title
|
+---------+------------------+
| 1001 | ACADEMY DINOSAUR |
+---------+------------------+
1 row in set (0.00 sec) |
当前session不能查询没有锁定的表
mysql> select film_id,title from film where film_id =
1001;
ERROR 1100 (HY000): Table ‘film‘ was not locked with LOCK
TABLES |
其他session可以查询或者更新未锁定的表
mysql> select film_id,title from film where film_id =
1001;
+---------+---------------+
| film_id |
title |
+---------+---------------+
| 1001 | update record |
+---------+---------------+
1 row in set (0.00 sec)
mysql> update film set title = ‘Test‘ where film_id =
1001;
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings:
0 |
当前session中插入或者更新锁定的表都会提示错误:
mysql> insert into film_text (film_id,title)
values(1002,‘Test‘);
ERROR 1099 (HY000): Table ‘film_text‘ was locked with a
READ lock and can‘t be updated
mysql> update film_text set title = ‘Test‘ where
film_id = 1001;
ERROR 1099 (HY000): Table ‘film_text‘ was locked with a
READ lock and can‘t be updated |
其他session更新锁定表会等待获得锁:
mysql> update film_text set title = ‘Test‘ where
film_id = 1001;
等待 |
释放锁
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec) |
等待 |
Session获得锁,更新操作完成:
mysql> update film_text set title = ‘Test‘ where
film_id = 1001;
Query OK, 1 row affected (1 min 0.71 sec)
Rows matched: 1 Changed: 1 Warnings:
0 |
session_1 |
session_2 |
获得表film_text的READ LOCAL锁定
mysql> lock table film_text read local;
Query OK, 0 rows affected (0.00 sec) |
|
当前session不能对锁定表进行更新或者插入操作:
mysql> insert into film_text (film_id,title)
values(1002,‘Test‘);
ERROR 1099 (HY000): Table ‘film_text‘ was locked with a
READ lock and can‘t be updated
mysql> update film_text set title = ‘Test‘ where
film_id = 1001;
ERROR 1099 (HY000): Table ‘film_text‘ was locked with a
READ lock and can‘t be updated |
其他session可以进行插入操作,但是更新会等待:
mysql> insert into film_text (film_id,title)
values(1002,‘Test‘);
Query OK, 1 row affected (0.00 sec)
mysql> update film_text set title = ‘Update Test‘ where
film_id = 1001;
等待 |
当前session不能访问其他session插入的记录:
mysql> select film_id,title from film_text where
film_id = 1002;
Empty set (0.00 sec) |
|
释放锁:
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec) |
等待 |
当前session解锁后可以获得其他session插入的记录:
mysql> select film_id,title from film_text where
film_id = 1002;
+---------+-------+
| film_id | title |
+---------+-------+
| 1002 | Test |
+---------+-------+
1 row in set (0.00 sec) |
Session2获得锁,更新操作完成:
mysql> update film_text set title = ‘Update Test‘ where
film_id = 1001;
Query OK, 1 row affected (1 min 17.75 sec)
Rows matched: 1 Changed: 1 Warnings:
0 |
读数据一致性及允许的并发副作用
隔离级别 |
读数据一致性 |
脏读 |
不可重复读 |
幻读 |
未提交读(Read uncommitted) |
最低级别,只能保证不读取物理上损坏的数据 |
是 |
是 |
是 |
已提交度(Read committed) |
语句级 |
否 |
是 |
是 |
可重复读(Repeatable read) |
事务级 |
否 |
否 |
是 |
可序列化(Serializable) |
最高级别,事务级 |
否 |
否 |
否 |
请求锁模式
是否兼容
当前锁模式 |
X |
IX |
S |
IS |
X |
冲突 |
冲突 |
冲突 |
冲突 |
IX |
冲突 |
兼容 |
冲突 |
兼容 |
S |
冲突 |
冲突 |
兼容 |
兼容 |
IS |
冲突 |
兼容 |
兼容 |
兼容 |
session_1 |
session_2 |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE
|
+----------+------------+-----------+
1 row in set (0.00 sec) |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE
|
+----------+------------+-----------+
1 row in set (0.00 sec) |
当前session对actor_id=178的记录加share mode 的共享锁:
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178 lock in share mode;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE
|
+----------+------------+-----------+
1 row in set (0.01 sec) |
|
其他session仍然可以查询记录,并也可以对该记录加share mode的共享锁:
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178 lock in share mode;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE
|
+----------+------------+-----------+
1 row in set (0.01 sec) | |
当前session对锁定的记录进行更新操作,等待锁:
mysql> update actor set last_name = ‘MONROE T‘ where
actor_id = 178;
等待 |
|
其他session也对该记录进行更新操作,则会导致死锁退出:
mysql> update actor set last_name = ‘MONROE T‘ where
actor_id = 178;
ERROR 1213 (40001): Deadlock found when trying to get
lock; try restarting transaction | |
获得锁后,可以成功更新:
mysql> update actor set last_name = ‘MONROE T‘ where
actor_id = 178;
Query OK, 1 row affected (17.67 sec)
Rows matched: 1 Changed: 1 Warnings:
0 |
session_1 |
session_2 |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE
|
+----------+------------+-----------+
1 row in set (0.00 sec) |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE
|
+----------+------------+-----------+
1 row in set (0.00 sec) |
当前session对actor_id=178的记录加for update的共享锁:
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178 for update;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE
|
+----------+------------+-----------+
1 row in set (0.00 sec) |
|
其他session可以查询该记录,但是不能对该记录加共享锁,会等待获得锁:
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE
|
+----------+------------+-----------+
1 row in set (0.00 sec)
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178 for update;
等待 | |
当前session可以对锁定的记录进行更新操作,更新后释放锁:
mysql> update actor set last_name = ‘MONROE T‘ where
actor_id = 178;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.01 sec) |
|
其他session获得锁,得到其他session提交的记录:
mysql> select actor_id,first_name,last_name from actor
where actor_id = 178 for update;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
| 178 |
LISA | MONROE T |
+----------+------------+-----------+
1 row in set (9.59 sec) |
session_1 |
session_2 |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tab_no_index where id
= 1 ;
+------+------+
| id | name |
+------+------+
| 1 | 1
|
+------+------+
1 row in set (0.00 sec) |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tab_no_index where id
= 2 ;
+------+------+
| id | name |
+------+------+
| 2 | 2
|
+------+------+
1 row in set (0.00 sec) |
mysql> select * from tab_no_index where id
= 1 for update;
+------+------+
| id | name |
+------+------+
| 1 | 1
|
+------+------+
1 row in set (0.00 sec) |
|
mysql> select * from tab_no_index where id
= 2 for update;
等待 |
session_1 |
session_2 |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tab_with_index where
id = 1 ;
+------+------+
| id | name |
+------+------+
| 1 | 1
|
+------+------+
1 row in set (0.00 sec) |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tab_with_index where
id = 2 ;
+------+------+
| id | name |
+------+------+
| 2 | 2
|
+------+------+
1 row in set (0.00 sec) |
mysql> select * from tab_with_index where
id = 1 for update;
+------+------+
| id | name |
+------+------+
| 1 | 1
|
+------+------+
1 row in set (0.00 sec) |
|
mysql> select * from tab_with_index where
id = 2 for update;
+------+------+
| id | name |
+------+------+
| 2 | 2
|
+------+------+
1 row in set (0.00
sec) |
session_1 |
session_2 |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) |
mysql> select * from tab_with_index where
id = 1 and name = ‘1‘ for update;
+------+------+
| id | name |
+------+------+
| 1 | 1
|
+------+------+
1 row in set (0.00 sec) |
|
虽然session_2访问的是和session_1不同的记录,但是因为使用了相同的索引,所以需要等待锁:
mysql> select * from tab_with_index where
id = 1 and name = ‘4‘ for update;
等待 |
session_1 |
session_2 |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) |
mysql> select * from tab_with_index where
id = 1 for update;
+------+------+
| id | name |
+------+------+
| 1 | 1
|
| 1 | 4
|
+------+------+
2 rows in set (0.00 sec) |
|
Session_2使用name的索引访问记录,因为记录没有被索引,所以可以获得锁:
mysql> select * from tab_with_index where
name = ‘2‘ for update;
+------+------+
| id | name |
+------+------+
| 2 | 2
|
+------+------+
1 row in set (0.00 sec) | |
由于访问的记录已经被session_1锁定,所以等待获得锁。:
mysql> select * from tab_with_index where
name = ‘4‘ for update; |
session_1 |
session_2 |
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec) |
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec) |
当前session对不存在的记录加for update的锁:
mysql> select * from emp where empid = 102 for
update;
Empty set (0.00 sec) |
|
这时,如果其他session插入empid为201的记录(注意:这条记录并不存在),也会出现锁等待:
mysql>insert into emp(empid,...) values(201,...);
阻塞等待 | |
Session_1 执行rollback:
mysql> rollback;
Query OK, 0 rows affected (13.04
sec) |
|
由于其他session_1回退后释放了Next-Key锁,当前session可以获得锁并成功插入记录:
mysql>insert into emp(empid,...) values(201,...);
Query OK, 1 row affected (13.35
sec) |
session_1 |
session_2 |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from target_tab;
Empty set (0.00 sec)
mysql> select * from source_tab where name = ‘1‘;
+----+------+----+
| d1 | name | d2 |
+----+------+----+
| 4 | 1 | 1 |
| 5 | 1 | 1 |
| 6 | 1 | 1 |
| 7 | 1 | 1 |
| 8 | 1 | 1 |
+----+------+----+
5 rows in set (0.00 sec) |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from target_tab;
Empty set (0.00 sec)
mysql> select * from source_tab where name = ‘1‘;
+----+------+----+
| d1 | name | d2 |
+----+------+----+
| 4 | 1 | 1 |
| 5 | 1 | 1 |
| 6 | 1 | 1 |
| 7 | 1 | 1 |
| 8 | 1 | 1 |
+----+------+----+
5 rows in set (0.00 sec) |
mysql> insert into target_tab select d1,name from source_tab where
name = ‘1‘;
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0 |
|
mysql> update source_tab set name = ‘1‘ where name = ‘8‘;
等待 | |
commit; |
|
返回结果
commit; |
session_1 |
session_2 |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql>set innodb_locks_unsafe_for_binlog=‘on‘
Query OK, 0 rows affected (0.00 sec)
mysql> select * from target_tab;
Empty set (0.00 sec)
mysql> select * from source_tab where name = ‘1‘;
+----+------+----+
| d1 | name | d2 |
+----+------+----+
| 4 | 1 | 1 |
| 5 | 1 | 1 |
| 6 | 1 | 1 |
| 7 | 1 | 1 |
| 8 | 1 | 1 |
+----+------+----+
5 rows in set (0.00 sec) |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from target_tab;
Empty set (0.00 sec)
mysql> select * from source_tab where name = ‘1‘;
+----+------+----+
| d1 | name | d2 |
+----+------+----+
| 4 | 1 | 1 |
| 5 | 1 | 1 |
| 6 | 1 | 1 |
| 7 | 1 | 1 |
| 8 | 1 | 1 |
+----+------+----+
5 rows in set (0.00 sec) |
mysql> insert into target_tab select d1,name from source_tab where
name = ‘1‘;
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0 |
|
session_1未提交,可以对session_1的select的记录进行更新操作。
mysql> update source_tab set name = ‘8‘ where name = ‘1‘;
Query OK, 5 rows affected (0.00 sec)
Rows matched: 5 Changed: 5 Warnings: 0
mysql> select * from source_tab where name = ‘8‘;
+----+------+----+
| d1 | name | d2 |
+----+------+----+
| 4 | 8 | 1 |
| 5 | 8 | 1 |
| 6 | 8 | 1 |
| 7 | 8 | 1 |
| 8 | 8 | 1 |
+----+------+----+
5 rows in set (0.00 sec) | |
更新操作先提交
mysql> commit;
Query OK, 0 rows affected (0.05 sec) | |
插入操作后提交
mysql> commit;
Query OK, 0 rows affected (0.07 sec) |
|
此时查看数据,target_tab中可以插入source_tab更新前的结果,这符合应用逻辑:
mysql> select * from source_tab where name = ‘8‘;
+----+------+----+
| d1 | name | d2 |
+----+------+----+
| 4 | 8 | 1 |
| 5 | 8 | 1 |
| 6 | 8 | 1 |
| 7 | 8 | 1 |
| 8 | 8 | 1 |
+----+------+----+
5 rows in set (0.00 sec)
mysql> select * from target_tab;
+------+------+
| id | name |
+------+------+
| 4 | 1.00 |
| 5 | 1.00 |
| 6 | 1.00 |
| 7 | 1.00 |
| 8 | 1.00 |
+------+------+
5 rows in set (0.00 sec) |
mysql> select * from tt1 where name = ‘1‘;
Empty set (0.00 sec)
mysql> select * from source_tab where name = ‘8‘;
+----+------+----+
| d1 | name | d2 |
+----+------+----+
| 4 | 8 | 1 |
| 5 | 8 | 1 |
| 6 | 8 | 1 |
| 7 | 8 | 1 |
| 8 | 8 | 1 |
+----+------+----+
5 rows in set (0.00 sec)
mysql> select * from target_tab;
+------+------+
| id | name |
+------+------+
| 4 | 1.00 |
| 5 | 1.00 |
| 6 | 1.00 |
| 7 | 1.00 |
| 8 | 1.00 |
+------+------+
5 rows in set (0.00 sec) |
隔离级别
一致性读和锁
SQL |
Read Uncommited |
Read Commited |
Repeatable Read |
Serializable | |
SQL |
条件 |
||||
select |
相等 |
None locks |
Consisten read/None lock |
Consisten read/None lock |
Share locks |
范围 |
None locks |
Consisten read/None lock |
Consisten read/None lock |
Share Next-Key | |
update |
相等 |
exclusive locks |
exclusive locks |
exclusive locks |
Exclusive locks |
范围 |
exclusive next-key |
exclusive next-key |
exclusive next-key |
exclusive next-key | |
Insert |
N/A |
exclusive locks |
exclusive locks |
exclusive locks |
exclusive locks |
replace |
无键冲突 |
exclusive locks |
exclusive locks |
exclusive locks |
exclusive locks |
键冲突 |
exclusive next-key |
exclusive next-key |
exclusive next-key |
exclusive next-key | |
delete |
相等 |
exclusive locks |
exclusive locks |
exclusive locks |
exclusive locks |
范围 |
exclusive next-key |
exclusive next-key |
exclusive next-key |
exclusive next-key | |
Select ... from ... Lock in share mode |
相等 |
Share locks |
Share locks |
Share locks |
Share locks |
范围 |
Share locks |
Share locks |
Share Next-Key |
Share Next-Key | |
Select * from ... For update |
相等 |
exclusive locks |
exclusive locks |
exclusive locks |
exclusive locks |
范围 |
exclusive locks |
Share locks |
exclusive next-key |
exclusive next-key | |
Insert into ... Select ...
(指源表锁) |
innodb_locks_unsafe_for_binlog=off |
Share Next-Key |
Share Next-Key |
Share Next-Key |
Share Next-Key |
innodb_locks_unsafe_for_binlog=on |
None locks |
Consisten read/None lock |
Consisten read/None lock |
Share Next-Key | |
create table ... Select ...
(指源表锁) |
innodb_locks_unsafe_for_binlog=off |
Share Next-Key |
Share Next-Key |
Share Next-Key |
Share Next-Key |
innodb_locks_unsafe_for_binlog=on |
None locks |
Consisten read/None lock |
Consisten read/None lock |
Share Next-Key |
session_1 |
session_2 |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from table_1 where where id=1 for update;
...
做一些其他处理... |
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from table_2 where id=1 for update;
... |
select * from table_2 where id =1 for update;
因session_2已取得排他锁,等待 |
做一些其他处理... |
mysql> select * from table_1 where where id=1 for update;
死锁 |
session_1 |
session_2 |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00
sec) |
mysql> select first_name,last_name from
actor where actor_id = 1 for update;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| PENELOPE | GUINESS
|
+------------+-----------+
1 row in set (0.00 sec) |
|
mysql> insert into country
(country_id,country) values(110,‘Test‘);
Query OK, 1 row affected (0.00
sec) | |
mysql> insert into country
(country_id,country) values(110,‘Test‘);
等待 |
|
mysql> select first_name,last_name from
actor where actor_id = 1 for update;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| PENELOPE | GUINESS
|
+------------+-----------+
1 row in set (0.00 sec) | |
mysql> insert into country
(country_id,country) values(110,‘Test‘);
ERROR 1213 (40001): Deadlock found when
trying to get lock; try restarting transaction |
session_1 |
session_2 |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) |
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00
sec) |
mysql> select first_name,last_name from
actor where actor_id = 1 for update;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| PENELOPE | GUINESS
|
+------------+-----------+
1 row in set (0.00 sec) |
|
mysql> select first_name,last_name from
actor where actor_id = 3 for update;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
|
ED |
CHASE |
+------------+-----------+
1 row in set (0.00 sec) | |
mysql> select first_name,last_name from
actor where actor_id = 3 for update;
等待 |
|
mysql> select first_name,last_name from
actor where actor_id = 1 for update;
ERROR 1213 (40001): Deadlock found when
trying to get lock; try restarting transaction | |
mysql> select first_name,last_name from
actor where actor_id = 3 for update;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
|
ED |
CHASE |
+------------+-----------+
1 row in set (4.71 sec) |
session_1 |
session_2 |
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec) |
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec) |
当前session对不存在的记录加for update的锁:
mysql> select actor_id,first_name,last_name from actor
where actor_id = 201 for update;
Empty set (0.00 sec) |
|
其他session也可以对不存在的记录加for update的锁:
mysql> select actor_id,first_name,last_name from actor
where actor_id = 201 for update;
Empty set (0.00 sec) | |
因为其他session也对该记录加了锁,所以当前的插入会等待:
mysql> insert into actor (actor_id ,
first_name , last_name) values(201,‘Lisa‘,‘Tom‘);
等待 |
|
因为其他session已经对记录进行了更新,这时候再插入记录就会提示死锁并退出:
mysql> insert into actor (actor_id,
first_name , last_name) values(201,‘Lisa‘,‘Tom‘);
ERROR 1213 (40001): Deadlock found when
trying to get lock; try restarting transaction | |
由于其他session已经退出,当前session可以获得锁并成功插入记录:
mysql> insert into actor (actor_id ,
first_name , last_name) values(201,‘Lisa‘,‘Tom‘);
Query OK, 1 row affected (13.35 sec) |
session_1 |
session_2 |
session_3 |
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)
mysql> set autocommit=0;
Query OK, 0 rows affected (0.01 sec) |
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)
mysql> set autocommit=0;
Query OK, 0 rows affected (0.01 sec) |
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)
mysql> set autocommit=0;
Query OK, 0 rows affected (0.01
sec) |
Session_1获得for update的共享锁:
mysql> select actor_id,
first_name,last_name from actor where actor_id = 201 for update;
Empty set (0.00 sec) |
由于记录不存在,session_2也可以获得for update的共享锁:
mysql> select actor_id,
first_name,last_name from actor where actor_id = 201 for update;
Empty set (0.00 sec) |
|
Session_1可以成功插入记录:
mysql> insert into actor
(actor_id,first_name,last_name) values(201,‘Lisa‘,‘Tom‘);
Query OK, 1 row affected (0.00 sec) |
||
Session_2插入申请等待获得锁:
mysql> insert into actor
(actor_id,first_name,last_name) values(201,‘Lisa‘,‘Tom‘);
等待 |
||
Session_1成功提交:
mysql> commit;
Query OK, 0 rows affected (0.04 sec) |
||
Session_2获得锁,发现插入记录主键重,这个时候抛出了异常,但是并没有释放共享锁:
mysql> insert into actor
(actor_id,first_name,last_name) values(201,‘Lisa‘,‘Tom‘);
ERROR 1062 (23000): Duplicate entry ‘201‘ for
key ‘PRIMARY‘ |
||
Session_3申请获得共享锁,因为session_2已经锁定该记录,所以session_3需要等待:
mysql> select actor_id,
first_name,last_name from actor where actor_id = 201 for update;
等待 | ||
这个时候,如果session_2直接对记录进行更新操作,则会抛出死锁的异常:
mysql> update actor set last_name=‘Lan‘
where actor_id = 201;
ERROR 1213 (40001): Deadlock found when
trying to get lock; try restarting transaction |
||
Session_2释放锁后,session_3获得锁:
mysql> select first_name, last_name from
actor where actor_id = 201 for update;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| Lisa |
Tom |
+------------+-----------+
1 row in set (31.12
sec) |
原文:http://www.cnblogs.com/bluecoder/p/3770128.html