1. 乐观锁
乐观锁是指在数据更新操作时,先读取数据并记录版本号,然后在更新时检查版本号是否发生变化,如果没有变化,则继续更新,否则回滚操作。乐观锁适用于并发度高的场景,因为乐观锁不会限制其他事务对数据的访问,如果数据冲突,则只需要回滚操作即可。 如果使用mybatis-plus 可以做直接配置
使用场景:适用于并发度高的场景,例如在高并发的电商网站中,多个用户同时对同一个商品进行下单操作。
示例 SQL:
-- 获取商品库存数量和版本号 SELECT stock, version FROM product WHERE id= 1; -- 更新商品库存数量 UPDATE product SET stock = stock - 1, version = version + 1 WHERE id = 1 AND version = 1;
2. 悲观锁
悲观锁是指在数据更新操作时,先加锁,然后再更新数据,更新完成后再释放锁。悲观锁适用于并发度低的场景,因为悲观锁会限制其他事务对数据的访问,如果没有必要,就会影响并发性能。MySQL 中的悲观锁主要有共享锁和排它锁两种。
使用场景:适用于并发度低的场景,例如在银行系统中,多个用户同时对同一个账户进行转账操作。
示例 SQL:
-- 对账户进行排它锁定 SELECT balance FROM account WHERE id = 1 FOR UPDATE; -- 用户 A 进行转账操作 UPDATE account SET balance = balance - 100 WHERE id = 1; -- 用户 B 进行转账操作 UPDATE account SET balance = balance + 100 WHERE id = 1; -- 释放锁 COMMIT;
3. 共享锁
共享锁是指多个事务可以共享同一份数据,但是不能同时进行更新操作。在获取共享锁之后,其他事务只能获取共享锁,不能获取排它锁。共享锁适用于读多写少的场景,可以提高并发度。
使用场景:适用于读多写少的场景,例如在新闻网站中,多个用户同时对同一篇文章进行阅读操作。
示例 SQL:
-- 对文章进行共享锁定 SELECT * FROM article WHERE id = 1 LOCK IN SHARE MODE; -- 用户 A、用户 B 和用户 C 同时读取文章内容 SELECT title, content FROM article WHERE id = 1; -- 释放锁 COMMIT;
4. 排它锁
排它锁是指在获取锁之后,其他事务不能获取任何类型的锁,也不能进行读取和更新操作。排它锁适用于写多读少的场景,可以保证数据的一致性和完整性。
使用场景:适用于写多读少的场景,例如在订单系统中,多个用户同时对同一份订单进行修改操作。
示例 SQL:
-- 对订单进行排它锁定 SELECT * FROM orders WHERE id = 1 FOR UPDATE; -- 用户 A 进行修改操作 UPDATE orders SET status = 'paid' WHERE id = 1; -- 用户 B 进行修改操作 UPDATE orders SET status = 'shipped' WHERE id = 1; -- 释放锁 COMMIT;
5. 行锁
行锁是指在对数据的某一行进行操作时,只对该行进行锁定,其他行不受影响。行锁适用于并发度高的场景,可以提高并发性能。
使用场景:适用于并发度高的场景,例如在社交网站中,多个用户同时对同一篇文章进行点赞操作。
示例 SQL:
-- 对点赞行进行行锁定 SELECT * FROM like WHERE user_id = 1 AND article_id = 1 FOR UPDATE; -- 用户 A 进行点赞操作 INSERT INTO like (user_id, article_id) VALUES (1, 1); -- 用户 B 进行点赞操作 INSERT INTO like (user_id, article_id) VALUES (2, 1); -- 用户 C进行点赞操作 INSERT INTO like (user_id, article_id) VALUES (3, 1); -- 释放锁 COMMIT;
6. 表锁
表锁是指在对整个表进行操作时,对整个表进行锁定,其他事务不能对该表进行任何操作。表锁适用于并发度低的场景,因为表锁会限制其他事务对数据的访问,如果没有必要,就会影响并发性能。
使用场景:适用于并发度低的场景,例如在定时任务系统中,多个任务同时对同一张表进行查询操作。
示例 SQL:
-- 对整个表进行表锁定 LOCK TABLES task READ; -- 多个任务进行查询操作 SELECT * FROM task WHERE status = 'pending'; -- 释放锁 UNLOCK TABLES;
总结
!! 锁的掌握,应该是每个开发人员必备的技能,同样锁的使用需要根据具体场景和业务需求进行调整和优化。如果锁的粒度过大或过小,都会影响并发性能和系统的稳定性。在使用锁时,需要根据具体情况选择不同的锁类型和锁粒度,以提高并发性能和保证数据安全。同时,需要注意锁的使用方式和时机,避免死锁和长时间等待的情况出现。