如果在事务中使用update语句更新但是条件中没有使用主键,会使用什么级别的锁?
在 MySQL 的 InnoDB 存储引擎中,当使用 UPDATE
语句更新数据时,即使条件中没有使用主键,InnoDB 仍然会使用行级锁,而非表级锁。具体的锁定行为和锁的范围取决于查询条件及其选择性。
更新操作的锁定行为
在事务中执行 UPDATE
语句时,InnoDB 会对符合条件的行记录加上排他锁(X 锁)。如果查询条件没有使用主键或唯一索引,InnoDB 会扫描表中的所有行,并对符合条件的行加锁,而不是直接锁住整个表。
锁定范围
-
使用主键或唯一索引:
- 如果条件中使用了主键或唯一索引,InnoDB 会通过索引快速定位到需要更新的行,并只对这些行加锁。
-
不使用主键或唯一索引:
- 如果条件中没有使用主键或唯一索引,InnoDB 需要进行全表扫描,找到所有符合条件的行,并对这些行加锁,导致可能的性能损耗。
示例
假设有一个 employees
表,结构如下:
CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100),department VARCHAR(100),salary DECIMAL(10, 2),INDEX (department)
) ENGINE=InnoDB;
情况一:条件中使用主键
-- 使用主键更新
UPDATE employees SET salary = salary * 1.1 WHERE id = 1;
在这种情况下,InnoDB 会通过主键索引快速定位到 id = 1
的行,并对该行加上排他锁。
情况二:条件中使用非主键索引
-- 使用非主键索引更新
UPDATE employees SET salary = salary * 1.1 WHERE department = 'Sales';
在这种情况下,InnoDB 会通过 department
索引扫描所有 department = 'Sales'
的行,并对这些行加上排他锁。
情况三:条件中不使用索引
-- 不使用索引更新
UPDATE employees SET salary = salary * 1.1 WHERE name = 'John';
在这种情况下,InnoDB 需要进行全表扫描,找到所有 name = 'John'
的行,并对这些行加上排他锁。
总结
- 使用主键/唯一索引:通过索引定位记录,并加行级锁。
- 不使用主键或唯一索引:全表扫描,找到符合条件的记录后加行级锁,但可能影响性能,尤其在数据量较大时。