mysql中的阻塞:
因为锁之间的不兼容性,有些时刻一个事务中的锁需要等待另外一个事务中的锁释放它所占用的资源,我们称这种方式为阻塞,有时候,为了确保事务的正常进行,就需要阻塞
在innoDB存储引擎中,参数innodb_lock_wait_timeout用来控制等待的时间(默认是50秒),innodb_rollback_on_timeout 用来设定是否在等待超时时对进行中的事务进行回滚操作(默认是OFF,代表不回滚)。参数innodb_lock_wait_timeout是动态的,可以在mysql数据库运行中进行调整
set @@innodb_lock_wait_timeout=60;
而 innodb_rollback_on_timeout 是静态的,不可在启动时进行修改,修改时会报错,它是只读变量
在默认情况下,innodb存储引擎不会回滚超时引发的错误异常,其实Innodb存储引擎在大部分情况下都不会对异常进行回滚
下面举例
mysql> select * from auth_operation;
+----+------+--------+---------------------+--------+--------------+---------+
| id | uid | op_uid | cr_time | action | address | remark |
+----+------+--------+---------------------+--------+--------------+---------+
| 1 | 3278 | 3240 | 2020-07-11 14:44:37 | 1 | 192.168.8.70 | ??????? |
| 2 | 3238 | 3240 | 2020-07-14 08:35:01 | 1 | 192.168.8.70 | ??????? |
| 3 | 3287 | 3240 | 2020-07-15 08:23:24 | 1 | 192.168.8.70 | ??????? |
+----+------+--------+---------------------+--------+--------------+---------+
3 rows in set (0.00 sec)
mysql> begin
-> ;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> select * from auth_operation where id < 3 for update;
+----+------+--------+---------------------+--------+--------------+---------+
| id | uid | op_uid | cr_time | action | address | remark |
+----+------+--------+---------------------+--------+--------------+---------+
| 1 | 3278 | 3240 | 2020-07-11 14:44:37 | 1 | 192.168.8.70 | ??????? |
| 2 | 3238 | 3240 | 2020-07-14 08:35:01 | 1 | 192.168.8.70 | ??????? |
+----+------+--------+---------------------+--------+--------------+---------+
2 rows in set (0.00 sec)
首先开启一个会话A,开启事务后查询,锁定了小于3的所有记录,然后在另外一个会话B中执行
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into auth_operation (id,uid,op_uid,cr_time,action,address) values
(4,3240,3240,'2020-07-14 08:35:01',1,'127.0.0.1')
-> ;
Query OK, 1 row affected (0.00 sec)
mysql>
mysql>
mysql> insert into auth_operation (id,uid,op_uid,cr_time,action,address) values
(2,3240,3240,'2020-07-14 08:35:01',1,'127.0.0.1')
-> ;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
我们看到插入数据id=4的时候是成功的,但是插入数据2的时候等待了60秒,报错,是因为在等待会话A释放这个资源,然后等待产生了超时,但是在超时后在select操作会发现,id=4是存在的
mysql> select * from auth_operation;
+----+------+--------+---------------------+--------+--------------+---------+
| id | uid | op_uid | cr_time | action | address | remark |
+----+------+--------+---------------------+--------+--------------+---------+
| 1 | 3278 | 3240 | 2020-07-11 14:44:37 | 1 | 192.168.8.70 | ??????? |
| 2 | 3238 | 3240 | 2020-07-14 08:35:01 | 1 | 192.168.8.70 | ??????? |
| 3 | 3287 | 3240 | 2020-07-15 08:23:24 | 1 | 192.168.8.70 | ??????? |
| 4 | 3240 | 3240 | 2020-07-14 08:35:01 | 1 | 127.0.0.1 | NULL |
+----+------+--------+---------------------+--------+--------------+---------+
4 rows in set (0.00 sec)
这是因为这时会话B中事务虽然抛出了异常,但是既没有进行commit 操作,也没有进行ROLLBACK,这种情况下很不安全(因为InnoDB引擎并不会对异常进行回滚),因此我们通常要在代码里面判断是commit ,还是ROLLBACK,再进行下一步操作!