當前位置 主頁 > 服務器問題 > win服務器問題匯總 > 最大化 縮小

    使用MySQL實現一個分布式鎖

    欄目:win服務器問題匯總 時間:2020-01-01 11:00

    介紹

    在分布式系統中,分布鎖是一個最基礎的工具類。例如,部署了2個有付款功能的微服務中,用戶有可能對一個訂單發起2次付款操作,而這2次請求可能被發到2個服務中,所以必須得用分布式鎖防止重復提交,獲取到鎖的服務正常進行付款操作,獲取不到鎖的服務提示重復操作。

    我司封裝了大量的基礎工具類,當我們想使用分布式鎖的時候只要做3件事情

    1.在數據庫中建globallocktable表
    2.引入相應的jar包
    3.在代碼中寫上@Autowired GlobalLockComponent globalLockComponent即可使用這個組件

    看完這篇文章你也可以用springboot-starter的方式實現一個同樣的功能。但我們不是用這個方式來實現的,另開一篇文章分析我們是怎么實現的。

    這篇文章先分析一下MySQL分布式的實現

    建表

    CREATE TABLE `globallocktable` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `lockKey` varchar(60) NOT NULL COMMENT '鎖名稱',
     `createTime` datetime NOT NULL COMMENT '創建時間',
     PRIMARY KEY (`id`),
     UNIQUE KEY `lockKey` (`lockKey`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='全局鎖';
    
    

    讓別人使用的組件

    @Component
    public class GlobalLockComponent {
     @Resource
     GlobalLockTableDAO globalLockDAO;
     /**
      * 嘗試獲得鎖,成功為true,失敗為false
      */
     public boolean tryLock(String key) {
      return GlobalLockUtil.tryLock(this.globalLockDAO, key);
     }
     /**
      * 如果已經有其他程序占用該鎖,并且超過timeoutMs(毫秒)時間,就強制清除這個鎖占用
      * 即根據key先刪除記錄,再添加記錄
      */
     public boolean tryLockWithClear(String key, Long timeoutMs) {
      return GlobalLockUtil.tryLockWithClear(this.globalLockDAO, key, timeoutMs);
     }
     /**
      * 釋放鎖,根據key刪除記錄
      */
     public void releasLock(String key) {
      GlobalLockUtil.releasLock(this.globalLockDAO, key);
     }
    }
    
    

    鎖對象定義如下

    public class GlobalLockTable {
    
     private Integer id;
     private String lockKey;
     private Date createTime;
     // 省略get和set方法
    }
    
    GlobalLockTableDAO定義如下
    
    public interface GlobalLockTableDAO {
     int deleteByPrimaryKey(Integer id);
     int deleteByLockKey(String lockKey);
     GlobalLockTable selectByLockKey(String key);
     int insertSelectiveWithTest(GlobalLockTable record);
    }

    具體加鎖和解鎖邏輯

    public class GlobalLockUtil {
     private static Logger logger = LoggerFactory.getLogger(GlobalLockUtil.class);
     private static GlobalLockTable tryLockInternal(GlobalLockTableDAO lockDAO, String key) {
      GlobalLockTable insert = new GlobalLockTable();
      insert.setCreateTime(new Date());
      insert.setLockKey(key);
      // 注意的地方1
      int count = lockDAO.insertSelectiveWithTest(insert);
      if (count == 0) {
       GlobalLockTable ready = lockDAO.selectByLockKey(key);
       logger.warn("can not lock the key: {}, {}, {}", insert.getLockKey(), ready.getCreateTime(),
         ready.getId());
       return ready;
      }
      logger.info("yes got the lock by key: {}", insert.getId(), insert.getLockKey());
      return null;
     }
     /** 超時清除鎖占用,并重新加鎖 **/
     public static boolean tryLockWithClear(GlobalLockTableDAO lockDAO, String key, Long timeoutMs) {
      GlobalLockTable lock = tryLockInternal(lockDAO, key);
      if (lock == null) return true;
      if (System.currentTimeMillis() - lock.getCreateTime().getTime() <= timeoutMs) {
       logger.warn("sorry, can not get the key. : {}, {}, {}", key, lock.getId(), lock.getCreateTime());
       return false;
      }
      logger.warn("the key already timeout wthin : {}, {}, will clear", key, timeoutMs);
      // 注意的地方2
      int count = lockDAO.deleteByPrimaryKey(lock.getId());
      if (count == 0) {
       logger.warn("sorry, the key already preemptived by others: {}, {}", lock.getId(), lock.getLockKey());
       return false;
      }
      lock = tryLockInternal(lockDAO, key);
      return lock != null ? false : true;
     }
     /** 加鎖 **/
     public static boolean tryLock(GlobalLockTableDAO lockDAO, String key) {
      return tryLockInternal(lockDAO, key) == null ? true : false;
     }
     /** 解鎖 **/
     public static void releasLock(GlobalLockTableDAO lockDAO, String key) {
      lockDAO.deleteByLockKey(key);
     }
    }
    
    下一篇:沒有了
青海十一选五开奖数据 股票资金配比? 平特一肖中奖赔率表 吉林彩票快三开奖查询 2019甘肃快三开奖结果 平特一肖怎么选 新加坡二分彩开奖查询 江苏11选5一天共几期 湖南幸运赛车开奖奖金 江西十一选五基本走势图 360十一运夺金走势图