乐观锁是一种非常宽松的锁机制,它不会锁定任何资源,而是在进行更新操作时检查该资源是否已被其他线程修改。乐观锁通常使用版本控制机制实现,每个数据行都有一个版本号,当进行更新操作时,会检查该版本号是否与数据库中的版本号相同,如果不同,则表示有其他线程已经更新该记录,此时应该重新获取数据并进行更新。
// 使用乐观锁实现更新
UPDATE table SET column = value, version = version + 1
WHERE id = xxx AND version = xxx
悲观锁是一种相对严谨的锁机制,它认为并发度较高的表会存在不少并发冲突的情况,因此在数据访问之前先锁定资源,直到当前线程执行完操作之后才会释放锁。悲观锁实现方式比较多,最常见的两种是行级锁和表级锁。
// 使用行级锁实现悲观锁,要求必须先使用 SELECT FOR UPDATE 获取锁
BEGIN;
SELECT * FROM table WHERE id = xxx FOR UPDATE;
UPDATE table SET column = value WHERE id = xxx;
COMMIT;
// 使用表级锁实现悲观锁,要求必须先使用 LOCK TABLE 获取锁
LOCK TABLE table WRITE;
SELECT * FROM table WHERE id = xxx;
UPDATE table SET column = value WHERE id = xxx;
UNLOCK TABLES;
根据实际的应用场景和数据库版本,乐观锁和悲观锁各有优缺点。乐观锁适用于并发度较低的情况,因为它不会占用太多的资源,但是如果数据访问十分频繁,会导致较高的版本检查成本。悲观锁则适用于并发度较高的情况,可以有效避免多线程并发访问资源的冲突,但是它也可能会引起资源竞争和死锁等问题。