文章目录
- 1、S锁和S锁互相兼容
- 2、S锁和X锁互斥
- 3、X锁和X锁也互斥
- 4、X锁和S锁也互斥
- 5、select * from account for update;
- 6、select * from account for update nowait;
- 7、select * from account for update skip locked;
1、S锁和S锁互相兼容
2、S锁和X锁互斥
3、X锁和X锁也互斥
4、X锁和S锁也互斥
5、select * from account for update;
SELECT * FROM account FOR UPDATE;
是一个SQL语句,通常用于数据库管理系统(如Oracle, PostgreSQL, MySQL的InnoDB存储引擎等)中,用于锁定所选的行以供后续更新。
以下是这条语句的详细解释:
-
SELECT * FROM account:
- 这部分是一个标准的SELECT语句,用于从
account
表中检索所有列和所有行。
- 这部分是一个标准的SELECT语句,用于从
-
FOR UPDATE:
- 这是一个锁定子句,用于锁定所选的行。一旦这些行被锁定,其他事务就不能修改或删除它们,直到当前事务完成(提交或回滚)。
- 这种锁定机制通常用于确保数据的一致性,特别是在涉及多个步骤的复杂事务中。
- 注意:不同的数据库管理系统对
FOR UPDATE
的锁定行为和范围可能有不同的实现。例如,在某些系统中,它可能只锁定所查询的行(行级锁定),而在其他系统中,它可能锁定整个表(表级锁定)。
使用场景:
假设你有一个在线银行系统,用户A正在尝试从他的账户中转账到用户B的账户。为了确保转账过程中账户余额的一致性,你可能需要执行以下步骤:
- 使用
SELECT * FROM account WHERE id = A's_account_id FOR UPDATE;
锁定用户A的账户。 - 检查用户A的账户余额是否足够进行转账。
- 如果余额足够,从用户A的账户中扣除相应金额,并增加用户B的账户余额。
- 提交事务,释放锁。
通过这种方式,你可以确保在用户A的账户被检查和更新之间,没有其他事务修改它,从而避免了潜在的数据不一致问题。
6、select * from account for update nowait;
SELECT * FROM account FOR UPDATE NOWAIT;
是一条SQL语句,通常用于数据库中的事务处理,特别是在需要锁定某些行以确保数据一致性的情况下。下面我会详细解释这条语句的每个部分:
-
SELECT * FROM account:
- 这部分是一个标准的
SELECT
查询,它从account
表中选择所有列(因为使用了*
)。
- 这部分是一个标准的
-
FOR UPDATE:
FOR UPDATE
是一个锁定子句,用于在事务中锁定选定的行。这意味着一旦某个事务执行了这个查询并锁定了某些行,其他尝试修改这些行的事务将被阻塞,直到第一个事务提交或回滚。- 这种锁定通常用于确保数据的完整性和一致性,尤其是在并发操作的环境中。
-
NOWAIT:
NOWAIT
是一个与FOR UPDATE
一起使用的选项。当指定了NOWAIT
时,如果请求的行当前已被其他事务锁定,那么查询将立即返回一个错误,而不是等待其他事务释放锁。- 这对于不希望因为等待锁而被阻塞的应用程序来说是非常有用的。通过立即得到一个错误,应用程序可以决定如何响应(例如,重试、报告错误给用户等)。
示例场景:
假设你有一个银行应用程序,两个用户(A和B)同时尝试从同一个账户(假设账户ID为123)中取款。为了避免出现“超支”的情况(即两个用户都成功取款,但账户余额不足以支付两次取款),数据库需要确保一次只有一个用户能够访问和修改该账户。
- 用户A开始一个事务,并执行
SELECT * FROM account WHERE id = 123 FOR UPDATE NOWAIT;
。假设此时账户余额足够支付用户A的取款请求。 - 在用户A的事务完成之前(即提交或回滚之前),用户B也尝试执行相同的查询。
- 因为用户A的事务已经锁定了账户ID为123的行,并且由于使用了
NOWAIT
选项,所以用户B的查询将立即返回一个错误,而不是等待用户A的事务完成。 - 用户B的应用程序可以捕获这个错误,并决定如何响应(例如,告诉用户B稍后再试)。
这样,通过使用FOR UPDATE NOWAIT
,你可以确保数据的一致性和完整性,同时减少因为等待锁而导致的延迟和可能的死锁情况。
7、select * from account for update skip locked;
SELECT * FROM account FOR UPDATE SKIP LOCKED;
这条SQL语句在支持该语法的数据库中(如Oracle、PostgreSQL等)用于在尝试锁定表或表中的行时跳过已经被其他事务锁定的行。这允许查询快速返回一个结果集,其中只包含当前事务可以立即锁定的行,而忽略那些已被其他事务锁定的行。
这条语句通常用于高并发的数据库环境中,特别是当多个事务需要同时访问并更新相同的资源时。通过使用SKIP LOCKED
选项,可以避免一个事务长时间等待另一个事务释放锁,从而提高整个系统的吞吐量和响应速度。
以下是这条语句的一些关键点:
- SELECT * FROM account:选择
account
表中的所有列。 - FOR UPDATE:指示数据库锁定所选的行,以便在后续的事务中更新它们。
- SKIP LOCKED:如果所选的行已被其他事务锁定,则跳过这些行并继续选择其他未被锁定的行。
示例场景:
假设你有一个在线购物网站,并且多个用户同时尝试购买同一件商品(库存有限)。为了确保商品不会被超卖,每次购买时都需要锁定相应的库存记录并进行更新。
- 用户A开始一个事务,并尝试锁定库存中数量大于0的商品。假设商品ID为123,当前库存为1。
- 在用户A的事务完成之前(即提交或回滚之前),用户B也尝试购买同一件商品。
- 由于用户A已经锁定了商品ID为123的记录,所以用户B的查询(使用
FOR UPDATE SKIP LOCKED
)将跳过已被锁定的记录,并继续查找其他未被锁定的商品。 - 如果此时没有其他商品可购买,用户B的事务将不会等待用户A的事务完成,而是立即返回一个空的结果集或相应的错误消息。
通过使用FOR UPDATE SKIP LOCKED
,你可以提高并发性能,避免不必要的等待,并为用户提供更快的响应速度。然而,请注意,这种机制并不能完全解决并发冲突,特别是在高并发的环境中。你可能还需要结合其他技术(如乐观锁、重试机制等)来确保数据的一致性和完整性。