❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」 ☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基
分布式系统中,分布式锁是一种常用的同步机制,通过MongoDB提供的findAndModify
原子操作,可以有效地实现分布式锁的功能。
MongoDB的锁机制主要用于保护数据的一致性和正确性。当多个客户端同时对同一文档进行操作时,MongoDB通过锁机制来确保每个操作的顺序和结果都是正确的。锁机制通过对文档进行加锁来实现,包括读锁和写锁。读锁允许多个客户端同时读取文档,但写锁则是互斥的,即同一时间只能有一个客户端持有写锁。
findAndModify
是MongoDB提供的一个非常强大的命令,它允许你同时执行查询和更新操作,并且这个操作是原子的。这意味着在findAndModify
执行期间,没有其他客户端可以修改被查询的文档,直到该命令完成。这个特性使其成为实现分布式锁的理想选择。
在分布式系统中,分布式锁需要满足以下几个基本要求:
首先,在MongoDB中创建一个专门的集合(如locks
)来存储锁信息。每个锁由一个文档表示,文档中包含了锁的关键信息,如锁名(lockName
)、持有者(holder
)、锁定时间(lockedAt
)、过期时间(expiresAt
)等。
当客户端需要获取锁时,它执行以下步骤:
findAndModify
命令查询locks
集合中的对应锁文档。findAndModify
命令成功更新了文档,则表示客户端成功获取了锁;如果更新失败(因为其他客户端已经设置了持有者或已过期时间已过),则表示锁已被占用或已过期。expiresAt
)来防止客户端在持有锁期间崩溃而无法释放锁。当过期时间到达时,其他客户端可以清除该锁(通过检查并更新expiresAt
和holder
字段)。当客户端完成操作后,它执行以下步骤来释放锁:
findAndModify
命令查询并更新locks
集合中的对应锁文档。在分布式系统中,实现锁机制是一项关键任务,用于控制对共享资源的访问,防止数据不一致。MongoDB的findAndModify
命令是一种强大的原子操作,可以用于实现简单的分布式锁。下面详细介绍其原理,并在Spring Boot环境中给出一个实现案例。
findAndModify
是MongoDB中的一个命令,它用于查找并更新一个文档,这个操作是原子的,意味着在查找和更新文档期间,不会有其他操作可以修改这个文档。利用这个特性,我们可以创建一个简单的分布式锁:
locks
),每个锁由一个文档表示。lockName
)、持有者(holder
)、锁定时间(lockedAt
)等。findAndModify
尝试更新集合中的一个文档,设置holder
和lockedAt
。如果更新成功,则表示获得了锁;如果失败(例如,因为其他客户端已经设置了holder
),则表示锁已被占用。findAndModify
操作来完成,将文档的holder
设置为null
或某个特定的释放标识。Spring Boot中可以使用Spring Data MongoDB与MongoDB的交互。
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "locks")
public class Lock {
@Id
private String id;
private String lockName;
private String holder;
private Date lockedAt;
// Getters and Setters
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
@Service
public class LockService {
@Autowired
private MongoTemplate mongoTemplate;
public boolean tryLock(String lockName, String clientId) {
Query query = new Query();
query.addCriteria(Criteria.where("lockName").is(lockName).and("holder").isNull());
Update update = new Update();
update.set("holder", clientId);
update.set("lockedAt", new Date());
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true);
Lock lock = mongoTemplate.findAndModify(query, update, options, Lock.class);
return lock != null && lock.getHolder().equals(clientId);
}
public void releaseLock(String lockName, String clientId) {
Query query = new Query();
query.addCriteria(Criteria.where("lockName").is(lockName).and("holder").is(clientId));
Update update = new Update();
update.set("holder", null);
mongoTemplate.findAndModify(query, update, Lock.class);
}
}
在服务层或控制器中,注入LockService
并调用tryLock
和releaseLock
方法来控制对共享资源的访问。
findAndModify
操作的延迟或失败。需要考虑这些因素对锁的性能和可靠性的影响。