Redis高级特性

本文涉及到的命令和数据类型请参见: Redis数据类型和基本操作

命令

  • keys * (可模糊匹配)
> set name mawenxia
OK
> set age 18
OK
> keys *
1) "age"
2) "name"
> keys n*  //模糊匹配
1) "name"
  • exists 判断key是否存在
> exists name
(integer) 1
  • 设置过期时间expire,查看过期时间ttl
> expire name 3600
(integer) 1
> ttl name
(integer) 3598
  • 取消过期时间persist
> persist name
(integer) 1
  • select 选择数据库。一个redis实例,数据库为0到15 一共16个,默认进入的是0数据库。可根据业务逻辑规则,或系统分类进行划分,存储在不同的库中
>SELECT 1
OK
>127.0.0.1:6379[1]> keys *    //这边多了一个[1]
(empty list or set)         //会发现之前的name和age都不在这里
  • move 移动数据到其他库中
127.0.0.1:6379[1]> set sex nan    //在库[1]中存入sex
OK
127.0.0.1:6379[1]> keys *
1) "sex"
127.0.0.1:6379[1]> move sex 0   //移动sex到库[0]中
(integer) 1
127.0.0.1:6379[1]> select 0         //切换到[0]数据库
OK
127.0.0.1:6379> get sex             //获取sex
"nan"                               //数据库[0]中已存在该数据
  • randomkey 随机返回数据库中的一个key 使用场景:抽奖。
  • rename 重命名key
  • echo 打印命令
  • dbsize 查看数据库key的数量
  • info 数据库信息查看 (CPU、内存、主从、集群、Client等信息) 。可用于监控平台
  • config get * 查看配置信息。可用于监控平台
  • flushdb 清空当前数据库 flushall 清空所有数据库

位操作

  • bitset
  • bitcount 计算二进制位中所有1的数量
  • bitop and/or destkey [key1,key2] 按位与按位或操作
  • 位操作在实时统计记录用户活跃量、点击量等应用中能提供高效的应用
  • 基于这个应用,在本公司实际项目中可统计每个实验室每天发生的阳性样本数。以各实验室id为key,366个二进制字节位表示每一天。只要某一天有阳性。就以天为offset把当前位的0改为1。最后可以用bitcount key offset1 offset2统计其他对比指标随意时间段内的阳性数。并且可以用bitop操作来快速对比各实验室间情况。

安全

由于redis速度极快,一个外部用户一秒内可以进行15万次的密码尝试,这意味着需要设定一个非常强大的密码来防止暴力破解,但是再复杂的密码,在大量的尝试下还是会被hit。建议加入计数器,超过数量之后,不允许再登录,锁定一段时间。

  • 密码设置

    vi redis.conf 找得到 requirepass *** 设置密码
    设置密码之后。需要先使用 auth *** 登录

事务

  • 使用multi 打开事务。执行完所有数据操作后,使用 exec 执行生效。
> multi
OK
set p1 1
QUEUED
> set p2 2
QUEUED
> set p3 3
QUEUED
> exec
1) OK
2) OK
3) OK
> keys p*
1) "p1"
2) "p3"
3) "p2"
  • 使用discard 取消事务
> multi
OK
> set p4 4
QUEUED
> set p5 5
QUEUED
> discard
OK
127.0.0.1:6379> keys p*
1) "p1"
2) "p3"
3) "p2"
  • 注意。目前redis还不能保证操作的原子性,可能部分回滚失败,比如事务中间出现报错的时候。
> get name
"mawenxia"
> get age
"19"
> multi    //开启事务
OK
> incr age    //年龄+1
QUEUED
> incr name    //名字+1
QUEUED
> exec      //执行
1) (integer) 20    //年龄+1成功
2) (error) ERR value is not an integer or out of range  //名字+1报错
> get age
"20"    //年龄+1成功。说明事务的回滚失败

Redis JavaAPI

  • 单实例下的redis是单线程的。
  • 单节点java操作redis一般使用Jedis
  • 在redis cluster 集群模式下,需要使用sharedJedis
/**
 * ShardJedis的测试类
 */
public class ShardJedisTest {

    private ShardedJedisPool sharedPool;

    @Before
    public void initJedis(){
        //Jedis池配置
        JedisPoolConfig config =new JedisPoolConfig();
        config.setTestOnBorrow(true);
        String hostA = "127.0.0.1";
        int portA = 6381;
        String hostB = "127.0.0.1";
        int portB = 6382;
        List jdsInfoList =new ArrayList(2);
        JedisShardInfo infoA = new JedisShardInfo(hostA, portA);
        JedisShardInfo infoB = new JedisShardInfo(hostB, portB);
        jdsInfoList.add(infoA);
        jdsInfoList.add(infoB);
        sharedPool =new ShardedJedisPool(config, jdsInfoList);
    }

    @Test
    public void testSetKV() throws InterruptedException {
        try {
            for (int i=0;i<50;i++){
                String key = "test"+i;
                ShardedJedis jedisClient = sharedPool.getResource();
                System.out.println(key+":"+jedisClient.getShard(key).getClient().getHost()+":"+jedisClient.getShard(key).getClient().getPort());
                System.out.println(jedisClient.set(key,Math.random()+""));
                jedisClient.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

}
  • 其他操作数据的API和命令行的操作基本一致,可参考Redis的基本命令来查找JedisAPI。
  • Jedis事务操作
//开启事务
Transaction tx = jedis.multi(); 
//执行操作1.2.3...
act1...
act2...
act3...
//提交。并接收操作结果
List resList = tx.exec();
 
 
  • Jedis Pool 使用连接池提高性能.操作结束必须返还连接
SharedJedis sj = pool.getResource();
...各类操作
//操作结束后返还连接
pool.returnResourceObject(sj);

Redis复杂查询技巧

比如做一个类似 select * from user where age = 18 and sex='m'的操作

  • 关键是设计一个合理的存储结构。存储结构如下。说明:把Set当做查询的条件存储,只存放数据的id。然后根据id取全部数据
数据类型 key (field) data
Hash id {"name":"zhangsan","age",18,"sex":"m"}...
Set userage18 key1,key2,key3...
Set usersexm key1,key2...
  • Hash类型的中存储全部user数据。set 类型的“userage18”中存储所有年龄为18的用户的id。同理,“usersexm”存储性别为"m"的用户id

  • 查询时,只要查询Set中符合条件的id,然后根据id取出需要的user数据即可

  • Set集合有"sinter"取交集,“sunion”取并集命令。来取出符合"age=18 and sex=m" 或 "age=18 or and sex=m" 的用户id

    Redis高级特性_第1张图片
    数据结构
    Redis高级特性_第2张图片
    sinter sunion 查询到用户key
  • 最后根据key来获取用户信息。

  • 这么做的好处:如果直接取出全部user数据在代码中判断符合条件的数据,很可能因为数据量过大,导致内存溢出。

分布式系统中的应用

  • setnx 可作为分布式锁使用。对指定的key,线程获取锁时进行setnx 如果能设置成功,即获得锁。操作结束删除。如果未结束。其他线程setnx将失败。
  • incr incrby 可作为各系统的主键生成器,既保证了主键的唯一性,还保证了主键的连续性,利于数据的合并及查找。
  • list push 和pop 可作为消息队列使用
  • zset实现延迟队列 业务场景:订单需要在未支付的30分钟后失效/72小时后设置默认评论等,如果轮询查库,数据量大了会拖死数据库。利用zset的score排序特性,以下单时间作为score,key来区分不同类型的延迟队列,value为mq消息体。这样每种类型的延迟队列只需要有一个任务来查询最小的score跟当前时间做对比判断是否超过时间,如果超过就取出value,发送mq消息,让对应的服务来消费,做对应的业务(订单失效/设置默认评论)。

Redis底层存储结构为 字节数组 故存储和取出时,注意要使用相同的字符集,否则将出现乱码。使用strlen 命令计算字符串长度时,也要特别注意,它计算的是字节数组的长度,并不是字符串长度,比如一个中文字,可能占用多个字节,故长度是会大于1的

你可能感兴趣的:(Redis高级特性)