여기서 mongod의 구현은 비교적 간단합니다. 주로 구성 서버 노드에 두 개의 잠금 컬렉션(잠금 및 잠금)을 생성하고 유지 관리하며, mongos는 시작 시 이 두 컬렉션에 생성됩니다. 그런 다음 레코드 상태(타임스탬프, 상태 포함)를 유지하여 현재 mongos 노드의 잠금 사용을 식별합니다. 여러 시스템 간에 잠금을 사용하려면 잠금 이름이 일치하는지 확인하세요. 이 레코드는 하나의 mongos 노드만 잠금을 얻을 수 있도록 해당 configsvr 노드 컬렉션에서 공유됩니다.
코드는 여러 서버에 배포됩니다. 즉, 분산 배포입니다.
여러 프로세스가 동시에 공유 리소스에 액세스합니다.
데이터베이스: mongo
java: mongo 작업 플러그인 클래스 MongoTemplate(maven 참조), 다음과 같습니다. ee
3. 구현 코드:
주요 구현 로직 및 외부 호출 메소드, 잠금 획득 및 getLock 호출, 잠금 해제 및 releaseLock 호출, 세부 사항은 다음과 같습니다.1 <!--mongodo开始--> 2 <dependency> 3 <groupId>org.springframework.data</groupId> 4 <artifactId>spring-data-mongodb</artifactId> 5 <version>1.8.2.RELEASE</version> 6 </dependency> 7 <dependency> 8 <groupId>org.springframework.data</groupId> 9 <artifactId>spring-data-commons</artifactId>10 <version>1.10.0.RELEASE</version>11 </dependency>12 <dependency>13 <groupId>org.mongodb</groupId>14 <artifactId>mongo-java-driver</artifactId>15 <version>2.13.0-rc2</version>16 </dependency>17 <!--mongodo结束-->
코드 보기
MongoLockDao 구현 코드:
1 import java.util.HashMap; 2 import java.util.List; 3 import java.util.Map; 4 5 6 public class MongoDistributedLock { 7 8 static MongoLockDao mongoLockDao; 9 10 static {11 mongoLockDao = SpringBeanUtils.getBean("mongoLockDao");12 } /**15 * 获得锁的步骤:16 * 1、首先判断锁是否被其他请求获得;如果没被其他请求获得则往下进行;17 * 2、判断锁资源是否过期,如果过期则释放锁资源;18 * 3.1、尝试获得锁资源,如果value=1,那么获得锁资源正常;(在当前请求已经获得锁的前提下,还可能有其他请求尝试去获得锁,此时会导致当前锁的过期时间被延长,由于延长时间在毫秒级,可以忽略。)19 * 3.2、value>1,则表示当前请求在尝试获取锁资源过程中,其他请求已经获取了锁资源,即当前请求没有获得锁;20 * !!!注意,不需要锁资源时,及时释放锁资源!!!。21 *22 * @param key23 * @param expire24 * @return25 */26 public static boolean getLock(String key, long expire) {27 List<MongoLock> mongoLocks = mongoLockDao.getByKey(key);28 //判断该锁是否被获得,锁已经被其他请求获得,直接返回29 if (mongoLocks.size() > 0 && mongoLocks.get(0).getExpire() >= System.currentTimeMillis()) {30 return false;31 }32 //释放过期的锁33 if (mongoLocks.size() > 0 && mongoLocks.get(0).getExpire() < System.currentTimeMillis()) {34 releaseLockExpire(key, System.currentTimeMillis());35 }36 //!!(在高并发前提下)在当前请求已经获得锁的前提下,还可能有其他请求尝试去获得锁,此时会导致当前锁的过期时间被延长,由于延长时间在毫秒级,可以忽略。37 Map<String, Object> mapResult = mongoLockDao.incrByWithExpire(key, 1, System.currentTimeMillis() + expire);38 //如果结果是1,代表当前请求获得锁39 if ((Integer) mapResult.get("value") == 1) {40 return true;41 //如果结果>1,表示当前请求在获取锁的过程中,锁已被其他请求获得。42 } else if ((Integer) mapResult.get("value") > 1) {43 return false;44 }45 return false;46 }47 48 /**49 * 释放锁50 *51 * @param key52 */53 public static void releaseLock(String key) {54 Map<String, Object> condition = new HashMap<>();55 condition.put("key", key);56 mongoLockDao.remove(condition);57 }58 59 /**60 * 释放过期锁61 *62 * @param key63 * @param expireTime64 */65 private static void releaseLockExpire(String key, long expireTime) {66 mongoLockDao.removeExpire(key, expireTime);67 }68 }
코드 보기
MongoLock 엔터티:
1 import org.springframework.data.mongodb.core.FindAndModifyOptions; 2 import org.springframework.data.mongodb.core.query.Criteria; 3 import org.springframework.data.mongodb.core.query.Query; 4 import org.springframework.data.mongodb.core.query.Update; 5 import org.springframework.stereotype.Repository; 6 7 import java.util.HashMap; 8 import java.util.List; 9 import java.util.Map;10 11 12 @Repository13 public class MongoLockDao <MongoLock> {14 private Class<?> clz;15 16 public Class<?> getClz() {17 if (clz == null) {18 //获取泛型的Class对象19 clz = ((Class<?>)20 (((ParameterizedType) (this.getClass().getGenericSuperclass())).getActualTypeArguments()[0]));21 }22 return clz;23 }24 25 /**26 * 返回指定key的数据27 *28 * @param key29 * @return30 */31 public List<MongoLock> getByKey(String key) {32 Query query = new Query();33 query.addCriteria(Criteria.where("key").is(key));34 return (List<MongoLock>) mongoTemplate.find(query, getClz());35 }36 37 38 /**39 * 指定key自增increment(原子加),并设置过期时间40 *41 * @param key42 * @param increment43 * @param expire44 * @return45 */46 public Map<String, Object> incrByWithExpire(String key, double increment, long expire) {47 //筛选48 Query query = new Query();49 query.addCriteria(new Criteria("key").is(key));50 51 //更新52 Update update = new Update();53 update.inc("value", increment);54 update.set("expire", expire);55 //可选项56 FindAndModifyOptions options = FindAndModifyOptions.options();57 //没有则新增58 options.upsert(true);59 //返回更新后的值60 options.returnNew(true);61 Map<String, Object> resultMap = new HashMap<>();62 resultMap.put("value", Double.valueOf(((MongoLock)63 mongoTemplate.findAndModify(query, update, options, getClz())).getValue()).intValue());64 resultMap.put("expire", Long.valueOf(((MongoLock)65 mongoTemplate.findAndModify(query, update, options, getClz())).getExpire()).longValue());66 return resultMap;67 }68 69 70 /**71 * 根据value删除过期的内容72 *73 * @param key74 * @param expireTime75 */76 public void removeExpire(String key, long expireTime) {77 Query query = new Query();78 query.addCriteria(Criteria.where("key").is(key));79 query.addCriteria(Criteria.where("expire").lt(expireTime));80 mongoTemplate.remove(query, getClz());81 }82 83 public void remove(Map<String, Object> condition) {84 Query query = new Query();85 Set<Map.Entry<String, Object>> set = condition.entrySet();86 int flag = 0;87 for (Map.Entry<String, Object> entry : set) {88 query.addCriteria(Criteria.where(entry.getKey()).is(entry.getValue()));89 flag = flag + 1;90 }91 if (flag == 0) {92 query = null;93 }94 mongoTemplate.remove(query, getClz());95 }96 97 }
코드 보기
네 가지 디자인 아이디어
전제: 몽고를 사용하세요. ID 증가를 구현하고 자체 증가 프로세스는 원자 작업, 즉 스레드로부터 안전합니다.1
releaseLockExpire(key, System.currentTimeMillis())를 releaseLockExpire(key)로 수정하면, 즉 만료 시간이 지나지 않은 경우 잠금을 해제하면 다음과 같은 상황이 발생합니다. 상황:1
2 , 방금 잠금 리소스를 획득한 상태였고, 이때 A와 잠금 해제 작업이 막 시작되었을 가능성이 있습니다.
그리고 releaseLockExpire(key, System.currentTimeMillis())는 방금 획득한 잠금 B가 실수로 삭제되지 않도록 잠금을 해제할 때 만료 시간을 결정하는 것을 의미합니다.
위 내용은 몽고 분산 잠금 예시 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!