reids实现分布式锁两种方式,单机,集群

 

一,redis如何实现锁的,wms csms两个项目到底用的哪一种方式?

1.1 wms 与springboot无关 

wms JedisCluster 所属jar 

1.2 csms 属于springboot依赖 

csms RedisTemplate 所属jar 

compile('org.springframework.boot:spring-boot-starter-redis')

还有跟下面这个依赖有区别吗

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>

二,具体如何实现,怎么连接配置信息的,有什么区别

2.1wms

通过RedisProperties加载配置信息,在通过属性配置实例化redis集群客户端JedisCluster,方法由客户端提供,底层实现

而csms中工具类方法,全部是springboot封装类RedisTemplate执行的,底层实现

集群配置

spring:  
  redis:
      clusterNodes:
            - 10.108.6.90:6179
            - 10.108.6.90:6279
            - 10.108.6.90:6379
            - 10.108.6.90:6479
            - 10.108.6.90:6579
            - 10.108.6.90:6679
      password: Allways_123
      expireSeconds: 120
      commandTimeout: 10000 #redis操作的超时时间
      pool:
         #最大连接数
          maxActive: 5000
         #最大空闲连接数
          maxIdle: 30
         #最小空闲连接数
          minIdle: 5
         #获取连接最大等待时间 ms #default -1
          maxWait: 10000
         #最大尝试连接数
          maxAttempts: 1 

属性类 

@Component
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
    private int expireSeconds;
    private List<String> clusterNodes = new ArrayList<String>();
    private String password;
    private int commandTimeout;
    private Map<String,Integer> pool = new HashMap<>();
    public int getExpireSeconds() {
        return expireSeconds;
    }
    public void setExpireSeconds(int expireSeconds) {
        this.expireSeconds = expireSeconds;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public int getCommandTimeout() {
        return commandTimeout;
    }
    public void setCommandTimeout(int commandTimeout) {
        this.commandTimeout = commandTimeout;
    }
    public Map<String, Integer> getPool() {
        return pool;
    }
    public void setPool(Map<String, Integer> pool) {
        this.pool = pool;
    }
	public List<String> getClusterNodes() {
		return clusterNodes;
	}
	public void setClusterNodes(List<String> clusterNodes) {
		this.clusterNodes = clusterNodes;
	}
}

配置类 

@Configuration
public class JedisClusterConfig {

    @Autowired
    private RedisProperties redisProperties;
    
    /**
    * 返回的JedisCluster是单例的,并且可以直接注入到其他类中去使用
    * @return
    */
    @Bean
    public JedisCluster getJedisCluster() {
        Set<HostAndPort> nodes = new HashSet<>();
        List<String> clusterNodes = redisProperties.getClusterNodes();
        for (String ipPort : clusterNodes) {
			String[] ipPortPair = ipPort.split(":");
			nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim())));
		}

        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(redisProperties.getPool().get("maxActive"));//最大连接数
        poolConfig.setMaxIdle(redisProperties.getPool().get("maxIdle"));//最大空闲连接数
        poolConfig.setMinIdle(redisProperties.getPool().get("minIdle"));//最小空闲连接数
        poolConfig.setMaxWaitMillis(redisProperties.getPool().get("maxWait").longValue());//连接最大等待时间
        return new JedisCluster(nodes,redisProperties.getCommandTimeout(),redisProperties.getCommandTimeout(),
            redisProperties.getPool().get("maxAttempts"),redisProperties.getPassword() ,poolConfig);//需要密码连接的创建对象方式
        
    }
}

工具类

@Component
public class RedisUtils {
	
	public static String 					REDIS_RECEIVE = "receive_";

    private static String redisCode = "utf-8";

    public static String 					REDIS_OURINV = "outinv_synchronized";
    private static final Long RELEASE_SUCCESS = 1L;
	

    public final static Logger logger = LogManager.getLogger(RedisUtils.class);
    @Autowired
    private JedisCluster jedisCluster;

    /**
     * 设置缓存
     *
     * @param key   缓存key
     * @param value 缓存value
     */
    public void set(String key, String value) {
        jedisCluster.set(key, value);
    }

    /**
     * 设置缓存,并且自己指定过期时间
     *
     * @param key
     * @param value
     * @param expireTime 过期时间
     */
    public void setWithExpireTime(String key, String value, int expireTime) {
        jedisCluster.setex(key, expireTime, value);
    }

    /**
     * 设置失效时间
     *
     * @param key
     * @param expireTime
     */
    public void expire(String key, int expireTime) {
        jedisCluster.setex(key, expireTime, jedisCluster.get(key));
    }

    /**
     * 获取指定key的缓存
     *
     * @param key
     */
    public String get(String key) {
        String value = jedisCluster.get(key);
        return value;
    }

    //解决redis异常
    public String getThrowRedis(String key) {
        try {
            get(key);
        } catch (Exception e) {
            return null;
        }
        return get(key);
    }


    /**
     * 设置缓存对象
     *
     * @param key        缓存key
     * @param obj        缓存value
     * @param expireTime 过期时间
     */
    public <T> void setObject(String key, T obj, int expireTime) {
        jedisCluster.setex(key, expireTime, JSON.toJSONString(obj));
    }

    /**
     * 获取指定key的缓存
     *
     * @param key---JSON.parseObject(value, User.class);
     */
    public String getObject(String key) {
        return jedisCluster.get(key);
    }

    /**
     * 判断当前key值 是否存在
     *
     * @param key
     */
    public boolean hasKey(String key) {
        return jedisCluster.exists(key);
    }

    /**
     * 删除指定key的缓存
     *
     * @param key
     */
    public void delete(String key) {
        jedisCluster.del(key);
    }

    /**
     * <pre>
     * 上锁
     * </pre>
     *
     * @param key
     */
    public synchronized void lock(String key) {
        if (StringUtils.isBlank(key)) {
            return;
        }
        this.set(key, new Date().toString());
    }

    /**
     * <pre>
     * 上锁
     * </pre>
     *
     * @param key
     */
    public synchronized void lockWithExpireTime(String key, int seconds) {
        if (StringUtils.isBlank(key)) {
            return;
        }
        jedisCluster.setex(key, seconds, new Date().toString());
    }

    /**
     * <pre>
     * 判断key是否被锁住了
     * </pre>
     *
     * @param key
     * @return
     */
    public synchronized Boolean isLock(String key) {
        if (StringUtils.isBlank(key)) {
            return false;
        }
        String stringDate = this.get(key);
        if (StringUtils.isBlank(stringDate)) {
            return false;
        }
        return true;
    }

    /**
     * <pre>
     * 解锁
     * </pre>
     *
     * @param key
     */
    public synchronized void unLock(String key) {
        if (StringUtils.isBlank(key)) {
            return;
        }
        this.delete(key);
    }

    /**
     * <pre>
     * 递增
     * </pre>
     *
     * @param key
     * @param by
     * @return
     */
    public Long incr(String key, Long by) {
        //默认原子操作
        if (by == null) {
            by = 1l;
        }
        return jedisCluster.incrBy(key, by);
    }

    /**
     * <pre>
     *
     * </pre>
     *
     * @param key
     * @param value
     * @param liveTime
     */
    public void set(String key, Object value, Long liveTime) {
        try {
            jedisCluster.setex(key.getBytes(redisCode), liveTime.intValue(), value.toString().getBytes(redisCode));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
    /**
     * <pre>
     * 批量删除keys
     * </pre>
     *
     * @param keys
     */
    public void delKeys(String[] keys) {
        if(keys != null) {
            for (String key : keys) {
                Long del = jedisCluster.del(key);
                System.out.println(del);
            }
        }
    }

    public void unlockValue(String keys, String value) {
        String lockValue = jedisCluster.get(keys);
        if (lockValue.equals(value)){
            jedisCluster.del(keys);
        }
    }
    
    public String[] keys(String pattern){
        TreeSet<String> keys = new TreeSet<>();
        Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
        for(String k : clusterNodes.keySet()){
            logger.debug("Getting keys from: {}", k);
            JedisPool jp = clusterNodes.get(k);
            Jedis connection = jp.getResource();
            try {
                keys.addAll(connection.keys(pattern));
            } catch(Exception e){
                logger.error("Getting keys error: {}", e);
            } finally{
                logger.debug("Connection closed.");
                connection.close();//用完一定要close这个链接!!!
            }
        }
        return keys.toArray(new String[] {});
    }

    /**
     * 设置缓存
     * @param key 缓存key
     * @param value 缓存value
     */
    public Long setnx(String key, String value) {
        return jedisCluster.setnx(key, value);
    }

    /**
     * <pre>
     * 上锁
     * </pre>
     *
     * @param key
     */
    public synchronized boolean locknx(String key){
        if(StringUtils.isBlank(key)){
            return false;
        }
        Long result = this.setnx(key, new Date().toString());

        if(result.equals(0L)){//如果返回0 则该key已经存在
            return false;
        }
        return true;
    }

    /**
     * <pre>
     * 上锁
     * </pre>
     *
     * @param key
     */
    public synchronized boolean locknx(String key, String value){
        if(StringUtils.isBlank(key)){
            return false;
        }
        Long result = this.setnx(key, value);

        if(result.equals(0L)){//如果返回0 则该key已经存在
            return false;
        }
        this.expire(key, 60*3);//设置失效时间3分钟
        return true;
    }
    
	public synchronized boolean lock(String lockKey,String requestId,int expireTime) {
		String result=jedisCluster.set(lockKey, requestId, "NX", "PX", expireTime);
		if("OK".equals(result)) {
			return true;
		}
		return false;
	}
	
	public synchronized boolean releaseLock(String lockKey,String requestId) {
		String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedisCluster.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
	}
}

2.2csms

而csms中工具类方法,全部是springboot封装类RedisTemplate执行的,具体执行方法又是由RedisConnection这个类完成

读取配置文件信息,还需要定义properties属性类吗,不可以从autoconfigtion中定义的直接读取吗,就算从这读取了,读取原理是什么,怎么用的?

单机配置

redis:
    database: 0
    host: 10.108.2.202
    port: 6379
    password: allways_123
    pool:
      #最大连接数
      max-active: 5000
      #获取连接最大等待时间 ms #default -1
      max-wait: 10000
      #最大空闲连接数
      max-idle: 30
      #最小空闲连接数
      min-idle: 5
    timeout: 0

工具类 

package com.anji.allways.base.redis;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.SerializationUtils;

/**
 * <pre>
 * RedisUtils
 * </pre>
 *
 * @author wanglong
 * @version $Id: RedisUtils.java, v 0.1 2018年3月16日 上午9:40:56 wanglong Exp $
 */
@Configuration
public class RedisUtils {

    @Resource
    private RedisTemplate<String, String> redisTemplate;
    
    private static String                 redisCode = "utf-8";
    
    /**
     * 默认过期时长,单位:秒
     */
    public static final long DEFAULT_EXPIRE = 60 * 3;

    /**
     * @param keys
     *            k
     * @return l
     */
    public long del(final String... keys) {
        return redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                long result = 0;
                for (int i = 0; i < keys.length; i++) {
                    try {
                        result += connection.del(keys[i].getBytes(redisCode));
                    } catch (UnsupportedEncodingException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                return result;
            }
        });
    }

    /**
     * @since 1.0
     * @param key
     *            k
     * @param value
     *            v
     * @param liveTime
     */
    public void set(final byte[] key, final byte[] value, final long liveTime) {
        redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                connection.set(key, value);
                if (liveTime > 0) {
                    connection.expire(key, liveTime);
                }
                return 1L;
            }
        });
    }

    /**
     * @since 1.0
     * @param key
     *            k
     * @param value
     *            v
     * @param liveTime
     */
    public void set(String key, String value, long liveTime) {
        try {
            this.set(key.getBytes(redisCode), value.getBytes(redisCode), liveTime);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param key
     *            k
     * @param value
     *            v
     */
    public void set(String key, String value) {
        this.set(key, value, 0L);
    }

    /**
     * @param key
     *            k
     * @param value
     *            v
     */
    public void set(byte[] key, byte[] value) {
        this.set(key, value, 0L);
    }

    /**
     * @param key
     *            l
     * @return s
     */
    public String get(final String key) {
        return redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                try {
                    byte[] data = connection.get(key.getBytes(redisCode));
                    if (data != null) {
                        return new String(data, redisCode);
                    }
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

    /**
     * @param pattern
     *            p
     * @return set
     */
    public Set<String> keys(String pattern) {
        return redisTemplate.keys(pattern);

    }

    /**
     * @param key
     *            k
     * @return b
     */
    public boolean exists(final String key) {
        return redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                try {
                    return connection.exists(key.getBytes(redisCode));
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return false;
            }
        });
    }

    /**
     * @return s
     */
    public String flushDB() {
        return flush();
    }

    public String flush() {
        return redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                connection.flushDb();
                return "ok";
            }
        });
    }

    /**
     * @return l
     */
    public long dbSize() {
        return dbs();
    }

    public long dbs() {
        return redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.dbSize();
            }
        });
    }

    /**
     * @return s
     */
    public String ping() {
        return pingRedis();
    }

    public String pingRedis() {
        return redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.ping();
            }
        });
    }

    /**
     * @since 1.0
     * @param key
     *            k
     * @return
     */
    public Object getObject(final String key) {
        return SerializationUtils.deserialize(redisTemplate.execute(new RedisCallback<byte[]>() {
            public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
                try {
                    return connection.get(key.getBytes(redisCode));
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                byte[] str = null;
                return str;
            }
        }));
    }

    /**
     * 将 key 的值设为 value ,当且仅当 key 不存在。 <br>
     * 若给定的 key 已经存在,则 SETNX 不做任何动作。
     * @param key
     * @param value
     * @return 设置成功,返回 1 。 设置失败,返回 0 。
     */
    public boolean setNX(final String key, final String value) {
        Object obj = null;
        try {
            obj = redisTemplate.execute(new RedisCallback<Object>() {
                @Override
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    StringRedisSerializer serializer = new StringRedisSerializer();
                    Boolean success = connection.setNX(serializer.serialize(key), serializer.serialize(value));
                    connection.close();
                    return success;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj != null ? (Boolean) obj : false;
    }

    /**
     * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。<br>
     * 当 key 存在但不是字符串类型时,返回一个错误。
     * @param key
     * @param value
     * @return 返回给定 key 的旧值。 当 key 没有旧值时,也即是, key 不存在时,返回 null 。
     */
    public String getSet(final String key, final String value) {
        Object obj = null;
        try {
            obj = redisTemplate.execute(new RedisCallback<Object>() {
                @Override
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    StringRedisSerializer serializer = new StringRedisSerializer();
                    byte[] ret = connection.getSet(serializer.serialize(key), serializer.serialize(value));
                    connection.close();
                    return serializer.deserialize(ret);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj != null ? (String) obj : null;
    }
    
    /**
     * 递增
     * @param key
     * @param by
     * @return value
     */
    public Long incr(String key,Long by) {
        //默认原子操作
        if(by == null) {
            by = 1l;
        }
        return redisTemplate.opsForValue().increment(key, by);
    }
    
    /**
     * 递增
     * @param key
     * @param by
     * @return value
     */
    public Long decr(String key,Long by) {
        return redisTemplate.opsForValue().increment(key, -by);
    }
    
    /**
     * <pre>
     * 上锁
     * </pre>
     *
     * @param key
     */
    public synchronized void lock(String key){
    	if(StringUtils.isBlank(key)){
    		return;
    	}
    	this.set(key, new Date().toString());
	}
    
	/**
	 * <pre>
	 * 判断key是否被锁住了
	 * </pre>
	 *
	 * @param key
	 * @return
	 */
	public synchronized Boolean isLock(String key){
		if(StringUtils.isBlank(key)){
    		return false;
    	}
		String stringDate = this.get(key);
		if(StringUtils.isBlank(stringDate)){
			return false;
		}
		return true;
	}
    
	/**
	 * <pre>
	 * 解锁
	 * </pre>
	 *
	 * @param key
	 */
	public synchronized void unLock(String key){
		if(StringUtils.isBlank(key)){
    		return;
    	}
		this.del(key);
	}
	
    /**
     * <pre>
     * 上锁 NX 加三分钟过期时间
     * ,上锁成功返回true,失败false
     * </pre>
     *
     * @param key
     */
    public synchronized boolean locknx(String key){
        if(StringUtils.isBlank(key)){
            return false;
        }
        boolean setNX = this.setNX(key, new Date().toString());
        //设置过期时间,三分钟
        this.redisTemplate.expire(key,DEFAULT_EXPIRE,TimeUnit.SECONDS);
        return setNX;
    }

    /**
     * 设置缓存,并且自己指定过期时间(废弃)
     * @param key
     * @param value
     * @param expireTime(秒)
     */
	public void setWithExpireTime(String key, String value, int expireTime) {
		 this.setNX(key, value);
	     this.redisTemplate.expire(key,expireTime,TimeUnit.SECONDS);
	}
	
    /**
    * 判断当前key值 是否存在
    *
    * @param key
    */	
	public boolean hasKey(String key) {
		String stringDate = this.get(key);
		if(StringUtils.isBlank(stringDate)){
			return false;
		}
		return true;
	}

	   /**
     * 刷新缓存时间
     * @param key
     * @param expireTime
     */
    public void expire(String key, int expireTime){
    	 this.setNX(key, this.get(key));
	     this.redisTemplate.expire(key,expireTime,TimeUnit.SECONDS);
    }
    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值