MySQL InnoDB引擎锁
InnoDB引擎出现死锁的情况如下:
(1)在应用中,如果不同的程序会并发存取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会。
| InnoDB引擎中表顺序操作不一致造成死锁 | |
| session1 | session2 |
| 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 t_user where id = 1 for update; +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | +----+----------+ 1 row in set (0.00 sec) |
|
| mysql> select * from t_temp_user where id = 1; +----+----------+----------+ | id | name | password | +----+----------+----------+ | 1 | zhangsan | 123456 | +----+----------+----------+ 1 row in set (0.00 sec) |
|
|
mysql> select * from t_temp_user where id = 1 for update; 等待 |
|
| mysql> select * from t_user where id = 1 for update; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting trans action mysql> |
|
|
mysql> select * from t_temp_user where id = 1 for update; +----+----------+----------+ |
|
(2)在程序以批量方式处理数据的时候,如果事先对数据排序,保证每个线程按固定的顺序来处理记录,也可以大大降低出现死锁的可能
| InnoDB引擎中表记录操作不一致造成死锁 | |
| session1 | session2 |
| 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 t_user where id = 1 for update; +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | +----+----------+ 1 row in set (0.00 sec) |
|
| mysql> select * from t_user where id = 2 for update; +----+------+ | id | name | +----+------+ | 2 | lisi | +----+------+ 1 row in set (0.00 sec) |
|
|
mysql> select * from t_user where id = 1 for update; mysql> |
|
| mysql> select * from t_user where id = 2 for update; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting trans action mysql> |
|
(3)在事务中如果需要更新数据时,应该先申请排他锁,而不应该先共享锁,再申请排他锁。
| InnoDB引擎中更新数据使用共享锁造成死锁 | |
| session1 | session2 |
| 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 t_user where id = 1 lock in share mode; +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | +----+----------+ 1 row in set (0.00 sec) |
|
| mysql> select * from t_user where id = 1 lock in share mode; +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | +----+----------+ 1 row in set (0.00 sec) |
|
| mysql> update t_user set name = 'zhangsan' where id = 1; | |
| mysql> update t_user set name = 'zhangsan' where id = 1; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting trans action mysql> |
|
| mysql> update t_user set name = 'zhangsan' where id = 1; Query OK, 0 rows affected (32.54 sec) Rows matched: 1 Changed: 0 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> |
|
(4)在repeatable-read隔离级别下,如果两个线程同时对相同条件记录用select * for update加排他锁,在没有符合记录条件的情况下,两个线程都会加锁成功
如果此时,同时插入一条新的记录,会造成死锁,需要将隔离级别设置read committed
| InnoDB引擎中隔离级别为repeatable-read造成死锁 | |
| session1 | session2 |
|
mysql> select @@tx_isolation; mysql> select * from t_user where id =5; 查看当前数据库的隔离级别,及不存在id = 5的记录 |
|
| 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 t_user where id = 5 for update; Empty set (0.00 sec) |
|
| mysql> select * from t_user where id = 5 for update; Empty set (0.00 sec) |
|
|
mysql> insert into t_user(name) values('qianqi'); dengdai |
|
| mysql> insert into t_user(name) values('qianqi'); ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting trans action mysql> |
|
| mysql> insert into t_user(name) values('qianqi'); Query OK, 1 row affected (36.04 sec) mysql> |
|
对于InnoDB引擎,如果没有索引,则创建的行锁是表锁,具体示例如下
| InnoDB引擎中表不存在索引,则建立的行锁,其实是表锁 | |
| session1 | session2 |
| mysql> show create table t_temp_user; +-------------+---------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------+ | Table | Create Table | +-------------+---------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------+ | t_temp_user | CREATE TABLE `t_temp_user` ( `id` int(19) default NULL, `name` varchar(30) default NULL, `password` varchar(30) default NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +-------------+---------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------+ 1 row in set (0.00 sec) mysql> |
|
| 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 t_temp_user where id = 1 for update; +------+----------+----------+ | id | name | password | +------+----------+----------+ | 1 | zhangsan | 123456 | +------+----------+----------+ 1 row in set (0.00 sec) mysql> |
mysql> select * from t_temp_user where id = 2 for update; 出现等待 |
| mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> |
|
| mysql> select * from t_temp_user where id = 2 for update; +------+------+----------+ | id | name | password | +------+------+----------+ | 2 | lisi | 123456 | +------+------+----------+ 1 row in set (7.07 sec) mysql> |
|
posted on 2015-02-08 21:03 zhaojunyang 阅读(185) 评论(0) 收藏 举报
浙公网安备 33010602011771号