为什么MySQL显式谓词锁定不允许谓词锁定之外的INSERT语句 [英] Why does MySQL explicit predicate locking disallow INSERT statements outside of the predicate lock
问题描述
假设我们有以下数据库表:
Assuming we have the following database tables:
create table department (
id bigint not null,
budget bigint not null,
name varchar(255),
primary key (id)
) ENGINE=InnoDB
create table employee (
id bigint not null,
name varchar(255),
salary bigint not null,
department_id bigint, primary key (id)
) ENGINE=InnoDB
alter table employee
add constraint FK_department_id
foreign key (department_id)
references department (id)
我们有2个departments
:
insert into department (name, budget, id)
values ('Hypersistence', 100000, 1)
insert into department (name, budget, id)
values ('Bitsystem', 10000, 2)
第一个部门的3个employees
:
insert into employee (department_id, name, salary, id)
values (1, 'John Doe 0', 30000, 0)
insert into employee (department_id, name, salary, id)
values (1, 'John Doe 1', 30000, 1)
insert into employee (department_id, name, salary, id)
values (1, 'John Doe 2', 30000, 2)
假设我们有两个并发用户:Alice和Bob.
Assuming we have two concurrent users: Alice and Bob.
首先,爱丽丝锁定了属于第一个department
的所有员工,并获得了该特定department
的薪金总和:
First, Alice locks all the employee belonging to the 1st department
and also gets the sum of salaries for that particular department
:
SELECT *
FROM employee
WHERE department_id = 1
FOR UPDATE
SELECT SUM(salary)
FROM employee
where department_id = 1
现在,与此同时,预计Bob不能使用相同的department_id
插入新的employee
:
Now, in the meanwhile, it's expected that Bob cannot insert a new employee
using the same department_id
:
insert into employee (department_id, name, salary, id)
values (1, `Carol`, 9000, 4)
com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:
Lock wait timeout exceeded; try restarting transaction
因此,该锁阻止Bob针对同一谓词发出插入.
So, the lock prevented Bob from issuing an insert against the same predicate.
但是,即使Bob试图将employee
插入不同的department
中,也会引发相同的异常:
However, the same exception is thrown even if Bob tries to insert an employee
in a different department
:
insert into employee (department_id, name, salary, id)
values (2, `Dave`, 9000, 5)
com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:
Lock wait timeout exceeded; try restarting transaction
最后一条insert语句使用第二个department_id
,因此该行不应与我们为其获取谓词锁定的select语句重叠.
This last insert statement is using the 2nd department_id
, so this row should not overlap with the select statement for which we acquired a predicate lock.
为什么MySQL会阻止第二个与第一笔交易获得的谓词锁不重叠的插入?
Why does MySQL prevent the second insert which is not overlapping with the predicate lock acquired by the first transaction?
在SQL Server上也可以观察到相同的行为.
The same behavior can be observed on SQL Server as well.
将隔离级别更改为READ_COMMITTED时,谓词锁定不会阻止Bob发出的两个插入语句中的任何一个.
When changing the isolation level to READ_COMMITTED, the predicate lock does not prevent any of the two insert statements issued by Bob.