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結束-->
主實現邏輯及外部調用方法,得到鎖調用getLock,釋放鎖調用releaseLock,詳情以下:html
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 } 13 14 /** 15 * 得到鎖的步驟: 16 * 一、首先判斷鎖是否被其餘請求得到;若是沒被其餘請求得到則往下進行; 17 * 二、判斷鎖資源是否過時,若是過時則釋放鎖資源; 18 * 3.一、嘗試得到鎖資源,若是value=1,那麼得到鎖資源正常;(在當前請求已經得到鎖的前提下,還可能有其餘請求嘗試去得到鎖,此時會致使當前鎖的過時時間被延長,因爲延長時間在毫秒級,能夠忽略。) 19 * 3.二、value>1,則表示當前請求在嘗試獲取鎖資源過程當中,其餘請求已經獲取了鎖資源,即當前請求沒有得到鎖; 20 * !!!注意,不須要鎖資源時,及時釋放鎖資源!!!。 21 * 22 * @param key 23 * @param expire 24 * @return 25 */ 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 key 52 */ 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 key 63 * @param expireTime 64 */ 65 private static void releaseLockExpire(String key, long expireTime) { 66 mongoLockDao.removeExpire(key, expireTime); 67 } 68 }
MongoLockDao實現代碼:java
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 @Repository 13 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 key 29 * @return 30 */ 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 key 42 * @param increment 43 * @param expire 44 * @return 45 */ 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 key 74 * @param expireTime 75 */ 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 }
MongoLock實體:spring
1 public class MongoLock { 2 3 private String key; 4 private double value; 5 private long expire; 6 7 public double getValue() { 8 return value; 9 } 10 11 public void setValue(double value) { 12 this.value = value; 13 } 14 15 public long getExpire() { 16 return expire; 17 } 18 19 public void setExpire(long expire) { 20 this.expire = expire; 21 } 22 23 public String getKey() { 24 return key; 25 } 26 27 public void setKey(String key) { 28 this.key = key; 29 } 30 }
前提:利用mongo實現id自增,且自增過程爲原子操做,即線程安全。mongodb
關於鎖過時時間 :數據庫
若是圖中代碼1releaseLockExpire(key, System.currentTimeMillis())修改成releaseLockExpire(key),即在釋放鎖的時候沒有傳入過時時間,會產生以下狀況:安全
致謝:感謝您的閱讀!轉載請加原文連接,謝謝!http://www.cnblogs.com/faaidong/p/7126716.html 服務器