InnoDB 中的意向锁(Intention Locks)是一种表级锁,用于表示事务打算对表中的某些行加锁。意向锁不会阻塞其他事务的操作,但在检测表锁冲突时会被考虑。
意向锁有两种类型:
- 意向共享锁(Intention Shared Lock, IS):事务打算获取表中某些行的共享锁。
- 意向排他锁(Intention Exclusive Lock, IX):事务打算获取表中某些行的排他锁。
意向锁的作用
意向锁的主要作用是加速锁检查。它们允许 InnoDB 在检测锁冲突时快速确定一个表是否可以安全地加锁,而无需逐行检查。
意向锁的工作原理
当一个事务试图在某些行上获取共享锁或排他锁时,它首先在表上获取相应的意向锁。如果两个事务在同一张表上获取了兼容的意向锁,它们可以在表的不同行上分别加锁。
例如:
- 如果事务 A 对某行加共享锁,那么它首先需要在表上加意向共享锁(IS)。
- 如果事务 B 对另一行加排他锁,那么它首先需要在表上加意向排他锁(IX)。
锁兼容性
IS | IX | S | X | |
---|---|---|---|---|
IS | Yes | Yes | Yes | No |
IX | Yes | Yes | No | No |
S | Yes | No | Yes | No |
X | No | No | No | No |
示例
假设有一个 employees
表:
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
salary DECIMAL(10, 2)
) ENGINE=InnoDB;
使用意向共享锁
BEGIN;
SELECT * FROM employees WHERE salary > 4000 LOCK IN SHARE MODE;
该语句在符合条件的记录上加了共享锁 (S 锁),同时在表上加了意向共享锁 (IS 锁)。
使用意向排他锁
BEGIN;
UPDATE employees SET salary = salary + 1000 WHERE id = 1;
该语句在 id = 1
的记录上加了排他锁 (X 锁),同时在表上加了意向排他锁 (IX 锁)。
Java 代码示例
假设通过 Java 代码来执行这些操作,可以使用 JDBC:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class InnoDBIntentionLockExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/yourdatabase";
String user = "yourusername";
String password = "yourpassword";
try (Connection conn = DriverManager.getConnection(url, user, password)) {
// 开始事务
conn.setAutoCommit(false);
// 加意向共享锁和共享锁查询
String query = "SELECT * FROM employees WHERE salary > 4000 LOCK IN SHARE MODE";
try (PreparedStatement pstmt = conn.prepareStatement(query);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name"));
}
}
// 提交事务
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
这个 Java 代码示例演示了如何使用 JDBC 来执行一个带有意向共享锁的查询。首先,设置连接为手动提交模式,然后执行一个带有 LOCK IN SHARE MODE
的查询以加锁。最后,提交事务。