MST

星途 面试题库

面试题:MySQL中在事务处理里,共享锁与排他锁如何配合使用以保证数据一致性?

在MySQL事务场景下,假设你有一个银行转账的操作,从账户A向账户B转账100元。请描述共享锁(S锁)和排他锁(X锁)应该在哪些操作步骤使用,以及如何使用,来确保转账过程中数据的一致性,避免出现并发问题。
25.5万 热度难度
数据库MySQL

知识考点

AI 面试

面试题答案

一键面试
  1. 开始事务
    START TRANSACTION;
    
  2. 对账户A加排他锁
    • 原因:为了防止其他事务在转账过程中修改账户A的余额,保证数据一致性。
    • 操作:
    SELECT balance FROM accounts WHERE account_id = 'A' FOR UPDATE;
    
    这里FOR UPDATE语句会对查询到的账户A记录加排他锁。
  3. 检查账户A余额是否足够
    • 读取账户A的余额,判断是否大于等于100。
    • 例如:
    SELECT balance INTO @a_balance FROM accounts WHERE account_id = 'A';
    IF @a_balance >= 100 THEN
        -- 余额足够,继续转账操作
    ELSE
        -- 余额不足,回滚事务
        ROLLBACK;
        RETURN;
    END IF;
    
  4. 对账户B加排他锁
    • 原因:防止其他事务在转账过程中修改账户B的余额。
    • 操作:
    SELECT balance FROM accounts WHERE account_id = 'B' FOR UPDATE;
    
  5. 执行转账操作
    • 更新账户A和账户B的余额。
    • 例如:
    UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';
    UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';
    
  6. 提交事务
    COMMIT;
    

在整个过程中,主要使用排他锁(X锁)来保证数据的一致性,没有用到共享锁(S锁)。因为共享锁主要用于读操作并发控制,而银行转账场景是写操作,需要排他锁来避免并发问题。如果在某些场景下,需要在读取账户余额时允许其他事务同时读取,可以在读取账户A和账户B余额时使用共享锁,但后续更新操作前仍然需要升级为排他锁。例如:

  1. 开始事务
    START TRANSACTION;
    
  2. 对账户A加共享锁
    SELECT balance FROM accounts WHERE account_id = 'A' LOCK IN SHARE MODE;
    
  3. 检查账户A余额是否足够:同上述步骤3。
  4. 将账户A的共享锁升级为排他锁
    SELECT balance FROM accounts WHERE account_id = 'A' FOR UPDATE;
    
  5. 对账户B加共享锁
    SELECT balance FROM accounts WHERE account_id = 'B' LOCK IN SHARE MODE;
    
  6. 将账户B的共享锁升级为排他锁
    SELECT balance FROM accounts WHERE account_id = 'B' FOR UPDATE;
    
  7. 执行转账操作和提交事务:同上述步骤5和6。