Redis入门及锁和计数的实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis入门及锁和计数的实现相关的知识,希望对你有一定的参考价值。

一、Redis简介
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
Redis支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

二、Redis的命令
命令行进入客户端

$ redis-cli

进入远程客户端

$ redis-cli -h host -p port -a password

查看redis信息

127.0.0.1:6379> info all

技术图片
1、String
增改

redis 127.0.0.1:6379> SET runoobkey redis
OK

redis 127.0.0.1:6379> GET runoobkey
"redis"

删(其他类型命令也一样)

redis 127.0.0.1:6379> DEL runoobkey
(integer) 1

2、Hash
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
增改

127.0.0.1:6379>  HMSET runoobkey name "redis tutorial" description "redis basic commands for caching" likes 20 visitors 23000
OK

127.0.0.1:6379>  HGETALL runoobkey
1) "name"
2) "redis tutorial"
3) "description"
4) "redis basic commands for caching"
5) "likes"
6) "20"
7) "visitors"
8) "23000"

3、List

redis 127.0.0.1:6379> LPUSH runoobkey redis
(integer) 1
redis 127.0.0.1:6379> LPUSH runoobkey mongodb
(integer) 2
redis 127.0.0.1:6379> LPUSH runoobkey mysql
(integer) 3

redis 127.0.0.1:6379> LRANGE runoobkey 0 10
1) "mysql"
2) "mongodb"
3) "redis"

4、Set
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

redis 127.0.0.1:6379> SADD runoobkey redis
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mongodb
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mysql
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mysql
(integer) 0

redis 127.0.0.1:6379> SMEMBERS runoobkey

1) "mysql"
2) "mongodb"
3) "redis"

5、sorted set
有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

redis 127.0.0.1:6379> ZADD runoobkey 1 redis
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 2 mongodb
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 0
redis 127.0.0.1:6379> ZADD runoobkey 4 mysql
(integer) 0

redis 127.0.0.1:6379> ZRANGE runoobkey 0 10 WITHSCORES

1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"

三、Jedis的应用
以maven工程为例,引入jar包

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
        Jedis jedis = new Jedis("localhost");
        System.out.println("连接成功");
        String key = "myname1";
        try{
                String result = jedis.set(key,"test_set_key");//插入数据
                System.out.println(key+":"+result);
                result = jedis.get(key);//查询数据
                if(null == result)result = "";
                System.out.println(key+":"+result);
        }catch (Exception e){
                e.printStackTrace();
                System.out.println("err:"+e.getMessage());
        }

打印结果:

连接成功
myname1:OK
myname1:test_set_key

四、结合SpringCloud应用
maven配置引入

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.8.1.RELEASE</version>
</dependency>

然后再service中引入RedisTemplate

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

增改
第一个参数key,第二个参数value,第三个参数过期时间,第四个参数过期时间单位

redisTemplate.opsForValue().set(key, value, 20, TimeUnit.DAYS);

String value = redisTemplate.opsForValue().get(key);

redisTemplate.delete(key);

五、分布式锁
Redis锁实现方法

@Value("${redisConfig.lockName}")
private String LOCK_PREFIX;// 锁名称 "redis_lock_"
@Value("${redisConfig.lockTime}")
private int LOCK_EXPIRE; // 加锁失效时间,毫秒
@Override
public boolean lock(String key){

        log.debug("LOCK_PREFIX:"+LOCK_PREFIX);
        log.debug("LOCK_EXPIRE:"+LOCK_EXPIRE);
        String lock = LOCK_PREFIX + key;
        // 利用lambda表达式
        return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
                long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
                //当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;
                Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
                if (acquire) {
                        return true;
                } else {
                        byte[] value = connection.get(lock.getBytes());
                        if (Objects.nonNull(value) && value.length > 0) {
                                long expireTime = Long.parseLong(new String(value));
                                // 如果锁已经过期
                                if (expireTime < System.currentTimeMillis()) {
                                        // 重新加锁,防止死锁
                                        byte[] oldValue = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
                                        return Long.parseLong(new String(oldValue)) < System.currentTimeMillis();//若未超时,返回true
                                }
                        }
                }
                return false;
        });
}

/**
 * 删除锁
 * @param key
 */
@Override
public void deleteLock(String key) {
        String lock = LOCK_PREFIX + key;
        redisTemplate.delete(lock);
}

调用方式:

if(redisService.lock(key)){
        //写业务
        redisService.deleteLock(key);
}else{
        log.debug("该主键的数据正在被其他服务处理,key:"+key);
}

六、计数
计数的方式主要采用redisTemplate的increment方法,第一个参数是key,第二个参数即增加的个数:

redisTemplate.opsForValue().increment("counter_total",1);

以上是关于Redis入门及锁和计数的实现的主要内容,如果未能解决你的问题,请参考以下文章

Redis实现分布式锁(设计模式应用实战)

锁及锁粒度的详细比喻

基于Redis的分布式锁和Redlock算法

Redis实现的分布式锁和分布式限流

基于Redis的分布式锁和Redlock算法

Redis(二十一)-Redis的事务冲突(悲观锁和乐观锁)