1. 程式人生 > 資料庫 >分散式鎖(五)——基於redisson的分散式鎖例項

分散式鎖(五)——基於redisson的分散式鎖例項

Redisson簡介

Redisson是一個在Redis的基礎上實現的Java駐記憶體資料網格(In-Memory Data Grid)。它不僅提供了一系列的分散式的Java常用物件,還提供了許多分散式服務。redisson參考文件。一定程度上他豐富了redis的資料型別 ,同時底層採用NIO的網路互動方式,進一步提升了分散式協調的相關能力。

更多關於Redisson的內容可以參見上述貼出的文件地址。Redisson實現分散式鎖相比redis就方便了許多。

springboot中引入Redisson

1、引入redisson的配置

spring.redisson.address=redis://127.0.0.1:6379

配置需要以redis開頭,畢竟在redisson的create原始碼中有這一段

public static URI create(String uri) {
    URI u = URI.create(uri);
    // Let's assuming most of the time it is OK.
    if (u.getHost() != null) {
        return u;
    }
    String s = uri.substring(0,uri.lastIndexOf(":")).replaceFirst("redis://","").replaceFirst("rediss://","");
    // Assuming this is an IPv6 format,other situations will be handled by
    // Netty at a later stage.
    return URI.create(uri.replace(s,"[" + s + "]"));
}

很明顯的看到這裡的字串處理的時候,會切割掉redis開頭或者rediss開頭,如果沒有則會丟擲異常。

2、將redisson交給容器管理

/**
 * redisson的分散式客戶端
 * @return
 */
@Bean
public RedissonClient redissonClient(){
    Config config = new Config();
    config.useSingleServer().setAddress(env.getProperty("spring.redisson.address"));
    RedissonClient client = Redisson.create(config);
    return client;
}

將這個bean交給有configuration註解的類進行託管。並返回RedissonClient(其實可以直接返回Redisson)

引入redisson,封裝各種操作

package com.learn.lockservce.component;

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * autor:liman
 * createtime:2020/1/30
 * comment: Redisson的分散式鎖元件。
 */
@Component
@Slf4j
public class RedissonLockComponent implements InitializingBean {

    @Autowired
    private RedissonClient redissonClient;

    private static Redisson redisson;

    //注入後的屬性設定方法,這裡其實有點稍微多此一舉,可以直接在容器託管的時候就返回Redisson就行。
    public void afterPropertiesSet() throws Exception {
        redisson = (Redisson) redissonClient;
    }

    /**
     * 獲取鎖
     * @param lockName
     * @return
     */
    public RLock acquireLock(String lockName){
        RLock lock = redisson.getLock(lockName);
        lock.lock();
        return lock;
    }

    /**
     * 釋放鎖
     * @param lock
     */
    public void releaseLock(RLock lock){
        lock.unlock();
    }
}

這裡封裝了獲取鎖和釋放鎖的操作,同時通過實現InitializingBean介面中的afterProperties的方法,完成了型別的強行轉換。這裡再順帶提一下,原始碼中可以看到Redisson是RedissonClient的一種實現。

在這裡插入圖片描述

同樣的業務處理

/**
 * 基於Redisson分散式鎖
 * @param productLockDto
 * @return
 */
@Transactional(rollbackFor = Exception.class)
public int updateStockRedisson(ProductLockDto productLockDto){
    int res = 0;
    boolean flag = true;
    while(flag){
		//獲取分散式鎖。
        RLock rLock = redissonLockComponent.acquireLock(String.valueOf(productLockDto.getId()));
        try{
            if(rLock!=null){
				//真正的業務處理
                flag=false;
                ProductLock productLockEntity = lockMapper.selectByPrimaryKey(productLockDto.getId());
                int leftStock = productLockEntity.getStock();
                if(productLockEntity!=null && productLockEntity.getStock().compareTo(productLockDto.getStock())>=0){
                    productLockEntity.setStock(productLockDto.getStock());
                    res = lockMapper.updateStockForNegative(productLockEntity);
                    if(res>0){
                        log.info("基於redisson獲取分散式鎖成功,剩餘stock:{}",leftStock-1);
                    }
                }
            }
        }catch (Exception e){
			//異常處理之後,繼續獲取鎖
            log.error("獲取鎖異常,{}",e.fillInStackTrace());
            flag=true;
        }finally {
			//正確釋放鎖
            if(rLock!=null){
                redissonLockComponent.releaseLock(rLock);
                flag=false;
            }
        }
    }
    return res;
}

和之前幾篇部落格,一樣的業務邏輯,一樣的程式碼主體,一樣的思想,這裡就不總結了,似乎可以看出大體上都是這樣的輪子

/**
 * 基於Redisson分散式鎖
 * @param productLockDto
 * @return
 */
@Transactional(rollbackFor = Exception.class)
public int updateStockRedisson(ProductLockDto productLockDto){
    int res = 0;
    boolean flag = true;
    while(flag){
		//獲取分散式鎖。
        RLock rLock = redissonLockComponent.acquireLock(String.valueOf(productLockDto.getId()));
        try{
            if(rLock!=null){
				//真正的業務處理
                
            }
        }catch (Exception e){
			//異常處理之後,繼續獲取鎖
            log.error("獲取鎖異常,{}",e.fillInStackTrace());
            flag=true;
        }finally {
			//正確釋放鎖
            
        }
    }
    return res;
}

總結

至此,關於幾種分散式鎖的簡單例項,總結完成,具體參見如下:

分散式鎖(一)——例項基本環境搭建

分散式鎖(二)——基於資料庫的分散式鎖例項

分散式鎖(三)——基於redis的分散式鎖例項

分散式鎖(四)——基於zookeeper的分散式鎖例項