mongo分布式鎖Java實現,mongojava

來源:互聯網
上載者:User

mongo分布式鎖Java實現,mongojava
一、分布式鎖使用情境:二、需要的技術:

 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結束-->
View Code 三、實現代碼:

  主實現邏輯及外部調用方法,獲得鎖調用getLock,釋放鎖調用releaseLock,詳情如下:

 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      * 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 }
View Code

  MongoLockDao實現代碼:

 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 }
View Code

  MongoLock實體:

 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 }
View Code四、設計思路

前提:利用mongo實現id自增,且自增過程為原子操作,即安全執行緒。

關於鎖到期時間 :

          如果圖中代碼1releaseLockExpire(key, System.currentTimeMillis())修改為releaseLockExpire(key),即在釋放鎖的時候沒有傳入到期時間,會產生如下情況:

 

 

致謝:感謝您的閱讀!轉載請加原文連結,謝謝!http://www.cnblogs.com/faaidong/p/7126716.html 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.