面试题答案
一键面试锁机制
- 原理:通过对共享数据(这里是账户A和账户B对应的余额数据)加锁,当一个转账请求执行时,先获取锁,其他转账请求只能等待锁释放后才能获取锁并执行。这样就保证了同一时间只有一个转账操作能对账户数据进行修改,从而避免并发问题。例如,在Java中可以使用
synchronized
关键字或ReentrantLock
来实现锁机制。 - 示例:
class BankAccount {
private int balance;
public BankAccount(int initialBalance) {
this.balance = initialBalance;
}
public synchronized void transfer(BankAccount to, int amount) {
if (this.balance >= amount) {
this.balance -= amount;
to.balance += amount;
}
}
}
数据库事务
- 原理:数据库事务具有原子性、一致性、隔离性和持久性(ACID特性)。在银行转账场景中,将从账户A扣钱和向账户B加钱的操作放在一个事务中。数据库会确保这个事务中的所有操作要么全部成功执行,要么全部回滚。例如,在MySQL数据库中,可以使用
START TRANSACTION
、COMMIT
和ROLLBACK
语句来管理事务。 - 示例:
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';
COMMIT;
分布式一致性协议(如两阶段提交协议 2PC)
- 原理:在分布式系统中,有一个协调者和多个参与者(这里的参与者可以是存储账户数据的不同节点)。第一阶段,协调者向所有参与者发送准备消息,参与者检查自身是否能够完成任务(如账户A余额是否足够),如果可以则回复准备就绪。第二阶段,如果所有参与者都准备就绪,协调者发送提交消息,参与者执行实际的转账操作;如果有任何一个参与者准备失败,协调者发送回滚消息,所有参与者回滚操作。
- 局限性:两阶段提交协议存在单点故障问题(协调者故障可能导致整个系统阻塞)、性能问题(涉及多次网络交互)等。
分布式锁(基于Redis等分布式缓存)
- 原理:利用Redis的单线程特性来实现分布式锁。当一个转账请求到达时,尝试在Redis中设置一个特定的键值对(例如以转账操作为标识的键),如果设置成功则表示获取到锁,该请求可以执行转账操作,操作完成后删除该键值对释放锁。如果设置失败则表示锁已被其他请求获取,该请求等待或重试。
- 示例(使用Jedis库在Java中实现):
import redis.clients.jedis.Jedis;
public class RedisDistributedLock {
private Jedis jedis;
private String lockKey;
private String lockValue;
public RedisDistributedLock(Jedis jedis, String lockKey) {
this.jedis = jedis;
this.lockKey = lockKey;
this.lockValue = java.util.UUID.randomUUID().toString();
}
public boolean acquireLock() {
return "OK".equals(jedis.set(lockKey, lockValue, "NX", "EX", 10));
}
public void releaseLock() {
if (lockValue.equals(jedis.get(lockKey))) {
jedis.del(lockKey);
}
}
}
在转账操作时使用:
Jedis jedis = new Jedis("localhost", 6379);
RedisDistributedLock lock = new RedisDistributedLock(jedis, "transfer_lock");
if (lock.acquireLock()) {
// 执行转账操作
lock.releaseLock();
}