redis的学习

 * 1.为什么要使用redis
 * 一般来说是为了提高性能,缓解数据库的压力,同时可以进行持久化操作RDB和AOF
 * 2.在liunx安装redis,可以将redis的bin,加入到环境变量中。
 * bin目录的常用命令:
 * Redis-benchmark :压力测试。标准是每秒80000次写操作,110000次读操作(服务启动起来后执行,类似安兔兔跑分)
 * Redis-check-dump:修改有问题的dump.rdb文件
 * Redis-sentinel:启动哨兵,集群使用
 * Redis-server 启动服务器
 * Redis-cli:启动客户端
 *
 * 3.数据库连接操作
 * select <dbip> :切换数据库 select 1
 * flushdb:清空当前数据库
 * dbsize:查看数据库数据个数
 * flushall:通杀全部库
 *
 * 4.key 的操作
 * key基本都是字符串
 * value是五种类型
 * keys pattern:查询符合指定表达式的所有key,支持*,?等
 * type key:查看类型
 * exists key:指定的key是否存在。0代表不存在,1代表存在
 * del key:删除指定的key
 * randomkey:在现在有的key中随机返回一个
 * expire key sceonds:为键值设置过期时间,单位是秒,过期后key会被redis移除
 * ttl key:查看key还有多少秒过期,-1表示永不过期,-2表示已过期
 * rename key newkey :重命名一个key,不管在不在都执行
 * renamenx key newkey:只有在newkey不存在时候能够执行成功,否则失败
 * /**
 * 1.为什么要使用redis
 * 一般来说是为了提高性能,缓解数据库的压力,同时可以进行持久化操作RDB和AOF
 * 2.在liunx安装redis,可以将redis的bin,加入到环境变量中。
 * bin目录的常用命令:
 * Redis-benchmark :压力测试。标准是每秒80000次写操作,110000次读操作(服务启动起来后执行,类似安兔兔跑分)
 * Redis-check-dump:修改有问题的dump.rdb文件
 * Redis-sentinel:启动哨兵,集群使用
 * Redis-server 启动服务器
 * Redis-cli:启动客户端
 *
 * 3.数据库连接操作
 * select <dbip> :切换数据库 select 1
 * flushdb:清空当前数据库
 * dbsize:查看数据库数据个数
 * flushall:通杀全部库
 *
 * 4.key 的操作
 * key基本都是字符串
 * value是五种类型
 * keys pattern:查询符合指定表达式的所有key,支持*,?等
 * type key:查看类型
 * exists key:指定的key是否存在。0代表不存在,1代表存在
 * del key:删除指定的key
 * randomkey:在现在有的key中随机返回一个
 * expire key sceonds:为键值设置过期时间,单位是秒,过期后key会被redis移除
 * ttl key:查看key还有多少秒过期,-1表示永不过期,-2表示已过期
 * rename key newkey :重命名一个key,不管在不在都执行
 * renamenx key newkey:只有在newkey不存在时候能够执行成功,否则失败
 * 
 * * hash 操作
 * HSET key field value 为 key 中的 field 赋值 value
 * HMSET key field value [field value ...] 为指定 key 批量设置 field-value
 * HSETNX key field value 当指定 key 的 field 不存在时,设置其 value
 * HGETALL key 获取指定 key 的所有信息(field 和 value)
 * HKEYS key 获取指定 key 的所有 field
 * HVALS key 获取指定 key 的所有 value
 * HLEN key 指定 key 的 field 个数
 * HGET key field 从 key 中根据 field 取出 value
 * HMGET key field [field ...] 为指定 key 获取多个 filed 的值
 * HEXISTS key field 指定 key 是否有 field
 * HINCRBY key field increment 为指定 key 的 field 加上增量 increment
 *
 * zset
 * ZADD key [score member ...] 添加
 * ZSCORE key member 返回指定值的分数
 * ZRANGE key start stop [WITHSCORES] 返回指定区间的值,可选择是否一起返回
 * scores
 * ZRANGEBYSCORE key min max [WITHSCORES]
 * [LIMIT offset count]
 * 在分数的指定区间内返回数据,从小到大排列
 * ZREVRANGEBYSCORE key max min
 * [WITHSCORES] [LIMIT offset count]
 * 在分数的指定区间内返回数据,从大到小排列
 * ZCARD key 返回集合中所有的元素的数量
 * ZCOUNT key min max 统计分数区间内的元素个数
 * ZREM key member 删除该集合下,指定值的元素
 * ZRANK key member 返回该值在集合中的排名,从 0 开始
 * ZINCRBY key increment value 为元素的 score 加上增
 * 
 * 5.持久化
 * reids的持久化分为两种
 * AOF和rdb
 * redis是基于内存的数据的数据存储
 * 当写入数据的时候会先从内存中读取数据,任何加载到磁盘中,以此来实现redis的持久化
 * RDB是基于快照存储,在指定时间内对数据进行快照存储
 * AOF是记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议保存写的操作到文件末尾,还可以对AOF文件进行后台重写,使得AOF文件不至于过大
 *
 * 当然,如果只是为了在服务器运行期间保留数据,完全不需要开启两种方式
 *
 * 一般来说建议是两种方式都开启
 * ,一般来说在重启的时候都会加载AOF文件来恢复原始数据,因为在通常情况下AOF文件保存的数据集要比RDBB保存的数据集要完整
 *
 * 优点:
 * RDB是一个非常紧凑性的文件,它保存了某个时间点的数据,非常适合数据集的备份
 * ,比如过去24小时内的数据,同时每天保存过去30天的数据。这样即使出了问题你也可以根据需求恢复到不同版本的数据集
 * RDB是一个紧凑的单一文件,很方便传送到另外一个远端数据中心或者亚马逊的s3,非常适用于灾难恢复
 * RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久方式可以最大化redis性能
 * AOF相比,在恢复大的数据集的时候,RDB方式会更快一些
 *
 * RDB的缺点:
 * 如果你希望在redis意外停止工作时候的情况下丢失的数据最少的话,rdb明显不适合你,虽然你可以配置不同的save时间点,但是redis要完整的保存数据集是一个比较繁重的工作,你通常每
 * 隔五分钟或者更久做一次完整的保存,万一再redis意外宕机的时候,你可能丢失几分钟的数据
 * RDB需要经常fork子进程来保存数据到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致redis再一些毫秒级内不能响应客户端的请求
 * ,如果数据集巨大并且cpu性能不是很好的情况下,这阵子情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度
 *
 *AOF
 * AOF 保存策略
 * appendfsync always:每次产生一条新的修改数据的命令都执行保存操作;效率低,但是安全!
 * appendfsync everysec:每秒执行一次保存操作。如果在未保存当前秒内操作时发生了断电,仍然会导致一部分数据
 * 丢失(即 1 秒钟的数据)。
 * appendfsync no:从不保存,将数据交给操作系统来处理。更快,也更不安全的选择。
 * 推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安
 *
 *AOF 文件的修复
 * 如果 AOF 文件中出现了残余命令,会导致服务器无法重启。此时需要借助 redis-check-aof 工具来修复!
 * 命令: redis-check-aof –fix
 *
 * AOF 的优缺点
 * 使用AOF会让你的redis更加耐久,你可以使用不同的fsync策列,一旦出现故障,你最多丢失1秒的数据
 * AOF文件是一个只进行追加的日志文件,不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等),未执行完的写入命令,你也可以通过redis-check-aof-fix工具修复这些问题。
 * redis可以再aof文件体积中变得过大时,自动的再后台对AOF进行重写,重写后端新AOF文件包含了恢复当前数据集的所需的最小命令集合。整个重写操作是绝对安全的
 * 。因为redis再创建aof文件的过程中,会将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的aof文件也不会丢失,而一旦新的aof文件创建完毕,redis就会替换掉旧的aof我加你,并开始对新的AOF
 * 文件进行追加操作。
 * Aof文件有序的保存了对数据库执行的所有写入操作,这些写入操作已redis协议格式保存,因此aof文件的内容非常容易被人读懂,对文件进行分析也很轻松,
 * 举个例子:如果不小心执行了flushall命令,但是只要还没有被重写,那么只要停止服务器,移除
 * aof文件末尾的flushall命令,并重启redis,就可以将数据集恢复到flushall执行之前的状态。
 *
 *
 * 缺点:
 * 对于相同的数据集来说,aof文件的体积通常要大于rdb文件的体积
 * 根据所使用的fsync策略,aof的速度可能会慢于rdb,在一般情况下,每秒fsync的性能依然非常的高,而关闭fsync可以让aof速度和rdb一样快,
 * 即使再高负荷之下也是如此,不过再处理巨大的写入载入时,rdb可以提供更有保证的最大延迟时间
 * * 如何看待数据“绝对”安全
 * Redis 作为内存数据库从本质上来说,如果不想牺牲性能,就不可能做到数据的“绝对”安全。
 * RDB 和 AOF 都只是尽可能在兼顾性能的前提下降低数据丢失的风险,如果真的发生数据丢失问题,尽可能
 * 减少损失。
 * 在整个项目的架构体系中,Redis 大部分情况是扮演“二级缓存”角色。
 * 二级缓存适合保存的数据
 *  经常要查询,很少被修改的数据。
 *  不是非常重要,允许出现偶尔的并发问题。
 *  不会被其他应用程序修改。
 * 如果 Redis 是作为缓存服务器,那么说明数据在 MySQL 这样的传统关系型数据库中是有正式版本的。数据
 * 最终以 MySQL 中的为准
 *
 * 为什么redis不支持回滚?
 * redis命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或者是命令用在了错误类型的键上面,这也就是说,=从实用性的角度来说,失败的命令是由于编程的错误造成的,而这些错误应该在开发
 * 的过程中被发现,而不应该出现在生产环境。
 * 因为不需要对回滚进行支持,所以redis的内部可以保持简单快速。
 * 还有就是回滚并不能解决编程错误代理的问题
 * 举个例子,如果你本来想通过incr命令将键值加1,不小心加2,又或者对错误类型的键执行ince,回滚是没有办法处理这些情况的
 * * 下线:
 * ①主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个 redis 服务器做出的
 * 下线判断。
 * ②客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel 实例在对 Master Server 做出
 * SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的 Master Server 下线
 * 判断,然后开启 failover.
 *
 *
 *
 * 工作原理:
 * ①每个 Sentinel 以每秒钟一次的频率向它所知的 Master,Slave 以及其他 Sentinel 实例发送一个 PING 命
 * 令 ;
 * ②如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所
 * 指定的值, 则这个实例会被 Sentinel 标记为主观下线;
 * ③如果一个 Master 被标记为主观下线,则正在监视这个 Master 的所有 Sentinel 要以每秒一次的频率确认
 * Master 的确进入了主观下线状态;
 * ④当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认 Master 的确进入了主
 * 观下线状态, 则 Master 会被标记为客观下线 ;
 * ⑤在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有 Master,Slave 发送 INFO 命令
 * ⑥当 Master 被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的
 * 频率会从 10 秒一次改为每秒一次 ;
 * ⑦若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除;
 * 若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除
 *
 * Jedis
 *
 * 使用连接池
 * 连接池的好处:节省每次连接 redis 服务带来的消耗,将创建好的连接实例反复利用;
 * 连接池常用参数
 * 参数 含义
 * MaxTotal 控制一个 pool 可分配多少个 jedis 实例,通过 pool.getResource()来获取;如果赋值为
 * -1,则表示不限制;如果 pool 已经分配了 MaxTotal 个 jedis 实例,则此时 pool 的状态
 * 为 exhausted。
 * maxIdle 控制一个 pool 最多有多少个状态为 idle(空闲)的 jedis 实例。
 * MaxWaitMillis 表示当 borrow 一个 jedis 实例时,最大的等待毫秒数,如果超过等待时间,则直接抛
 * JedisConnectionException。
 * testOnBorrow 获得一个 jedis 实例的时候是否检查连接可用性(ping());如果为 true,则得到的 jedis
 * 实例均是可用的
 * * 5. 常用五大数据类型:string,list,set,zset,hash
 * string:redis中一个字符最大512m
 * SET key value 添加键值对
 * GET key 查询指定 key 的值
 * APPEND key value 将给定的 value 追加到原值的末尾
 * STRLEN key 获取值的长度
 * SETNX key value 只有在 key 不存在时设置 key 的值
 * INCR key 指定 key 的值自增 1,只对数字有效
 * DECR key 指定 key 的值自减 1,只对数字有效
 * INCRBY key num 自增 num
 * DECRBY key num 自减 num
 * MSET key1 value1 key2 value2… 同时设置多个 key-value 对
 * MGET key1 key2 同时获取一个或多个 value
 * MSETNX key1 value1 key2 value2 当 key 不存在时,设置多个 key-value 对
 * GETRANGE key 起始索引 结束索引 获取指定范围的值,都是闭区间
 * SETRANGE key 起始索引 value 从起始位置开始覆写指定的值
 * GETSET key value 以新换旧,同时获取旧值
 * SETEX key 过期时间 value 设置键值的同时,设置过期时间,单位秒
 *
 * list:双链表
 * LPUSH/RPUSH KEY value1,value2 从左边或者右边压入一个或者多个值,头尾效率高,中间效率低
 * Lpop/Rpop key 删除
 * Lrange key start stop 查看指定区间的数据 0,-1
 * Lindex key index 按照索引下标获取元素
 * llie key 获取长度
 * LINSERT key BEFORE|AFTER value newvalue 在指定 value 的前后插入 newvalue
 * LREM key n value 从左边删除 n 个 value
 * LSET key index value 把指定索引位置的元素替换为另一个值
 * LTRIM key start stop 仅保留指定区间的数据
 * RPOPLPUSH key1 key2 从 key1 右边弹出一个值,左侧压入到 key2
 *
 * set 操作
 * set 是无序的,且是不可重复的。
 * SADD key member [member ...] 将一个或多个 member 元素加入到集合 key 当中,已
 * 经存在于集合的 member 元素将被忽略。
 * SMEMBERS key 取出该集合的所有值
 * SISMEMBER key value 判断集合<key>是否为含有该<value>值,有返回 1,没有
 * 返回 0
 * SCARD key 返回集合中元素的数量
 * SREM key member [member ...] 从集合中删除元素
 * SPOP key [count] 从集合中随机弹出 count 个数量的元素,count 不指定就
 * 弹出 1 个
 * SRANDMEMBER key [count] 从集合中随机返回 count 个数量的元素,count 不指定就
 * 返回 1 个
 * SINTER key [key ...] 将指定的集合进行“交集”操作
 * SINTERSTORE dest key [key ...] 取交集,另存为一个 set
 * SUNION key [key ...] 将指定的集合执行“并集”操作
 * SUNIONSTORE dest key [key ...] 取并集,另存为 set
 * SDIFF key [key ...] 将指定的集合执行“差集”操作
 * SDIFFSTORE dest key [key ...] 取差集,另存为 set
 * * 主从复制:
 * 配置多台redis。根据主机和从机的身份分开。主机数据更新后,根据配置和策略,自动同步到备机
 * master以写为主,slaveof以读为主,二者之间自动同步数据。
 * 目的:读写分离提高redis性能
 * 避免单点故障,发生灾难能够快速恢复
 * 原理:
 * 每次从机联通后,都会给主机发送sync指令,主机立刻进行存盘操作,发送RDB文件给从机,收到从机文件后,进行全盘加载,之后主机每次的写操作,都会立刻发送给从机,从机执行相同的命令
 *
 *
 * 主从建立
 * 1. 临时建立
 * 原则:配从不配主。
 * 配置:在从服务器上执行 SLAVEOF ip:port 命令;
 * 查看:执行 info replication
 *
 * 2 永久建立
 * 在从机的配置文件中,编写 slaveof
 *
 * 3.恢复身份
 * 执行命令 slaveof no noe 恢复自由身
 *
 *
 *
 * 4. 主从常见问题
 * ①从机是从头开始复制主机的信息,还是只复制切入以后的信息?
 * 答:从头开始复制,即完全复制。
 * ②从机是否可以写?
 * 答:不能
 * ③主机 shutdown 后,从机是上位还是原地待命?
 * 答:原地待命
 * ④主机又回来了后,主机新增记录,从机还能否顺利复制?
 * 答:可以
 * ⑤从机宕机后,重启,宕机期间主机的新增记录,丛集是否会顺利复制?
 * 答:可以
 * ⑥其中一台从机 down 后重启,能否重认旧主?
 * 答:不一定,看配置文件中是否配置了 slaveof
 * ⑦如果两台从机都从主机同步数据,此时主机的 IO 压力会增大,如何解决?
 * 答:按照主---从(主)---从模式配置
 *

测试:

String
public class RedisClient {
public static void main(String[] args) {
        Jedis jedis = new Jedis("172.16.19.80",6379);
        String ping = jedis.ping();
        System.out.println(ping);

        //获取所有key
        jedis.set("a","1");
       Set<String> keys = jedis.keys("a");
       System.out.println(keys);

       for (String key : keys) {
           System.out.println(key);
        }
        //判断是否存在某个key
       System.out.println("是否存在k2:"+jedis.exists("k2"));
        //测试某个key的过期时间
        System.out.println("k1的存活时间:"+jedis.ttl("k2"));

        jedis.close();

Map

public class RedisClient {
public static void main(String[] args) {
//连接指定的redis,需要ip地址和端口号
        Jedis jedis1 = new Jedis("172.16.19.80",6379);
        jedis1.zadd("myZset", 100, "math");
//将多个数据封装为一个map
        Map<String, Double> subject=new HashMap<String, Double>();
        subject.put("chinese", 88d);
        subject.put("english", 86d);
//批量添加数据
        jedis1.zadd("myZset", subject);
        Set<String> zset = jedis1.zrange("myZset", 0, -1);
        for (String val : zset) {
            System.out.println(val);
        }
//关闭连接
        jedis1.close();

list

public class RedisClient {
public static void main(String[] args) {
//连接指定的redis,需要ip地址和端口号
        Jedis jedis = new Jedis("172.16.19.80",6379);
        jedis.lpush("mylist", "1","2","3","4");
        List<String> list = jedis.lrange("mylist", 0, -1);
        for (String element : list) {
            System.out.println(element);
        }
       //关闭连接
        jedis.close();

Set

public class RedisClient {
public static void main(String[] args) {
//连接指定的redis,需要ip地址和端口号
        Jedis jedis = new Jedis("172.16.19.80",6379);
        //添加元素
        jedis.sadd("mySet", "Jack","Marry","Tom","Tony");
        //删除指定元素
        jedis.srem("mySet", "Tony");
        //获取指定key的元素
        Set<String> smembers = jedis.smembers("mySet");
        for (String member : smembers) {
            System.out.println(member);
        }

        //关闭连接
        jedis.close();



zset

public class RedisClient {
public static void main(String[] args) {
       //连接指定的redis,需要ip地址和端口号
        Jedis jedis = new Jedis("172.16.19.80",6379);
        jedis.zadd("myZset", 100, "math");
        //将多个数据封装为一个map
        Map<String, Double> subject=new HashMap<String, Double>();
        subject.put("chinese", 88d);
        subject.put("english", 86d);
       //批量添加数据
        jedis.zadd("myZset", subject);
        Set<String> zset = jedis.zrange("myZset", 0, -1);
        for (String val : zset) {
            System.out.println(val);
        }
       //关闭连接
        jedis.close();



数据库的设置

//默认的连接池配置
        GenericObjectPoolConfig objectGenericObjectPoolConfig = new GenericObjectPoolConfig();
        System.out.println("========="+objectGenericObjectPoolConfig);
        JedisPool jedisPool = new JedisPool(objectGenericObjectPoolConfig,"172.16.19.80",6379,60000);
        Jedis resource = jedisPool.getResource();
        String ping = resource.ping();
        System.out.println(resource);
        System.out.println(ping);
        resource.close();
        jedisPool.close();

数据库工具类

/**
 * @author 180937
 * 数据库连接池
 */
public class JedisPoolUtil {

    @Autowired
    RedisTemplate redisTemplate;

    private static volatile JedisPool jedisPool = null;
    private JedisPoolUtil() {

    }

    public static JedisPool getJedisPoolInstance() {
        if (null == jedisPool) {
            synchronized (JedisPoolUtil.class) {
                if (null == jedisPool) {
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    poolConfig.setMaxTotal(200);//最大连接数
                    poolConfig.setMaxIdle(32);//最大空闲连接数
                    //获取连接时的最大等待毫秒数,如果超时就抛异常,默认-1
                    poolConfig.setMaxWaitMillis(100 * 1000);
                    //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
                    poolConfig.setBlockWhenExhausted(true);
                    //在获取连接的时候检查有效性, 默认false
                    poolConfig.setTestOnBorrow(true);
                    jedisPool = new JedisPool(poolConfig, "172.16.19.80", 6379, 60000);
                }
            }
        }
        return jedisPool;

    }


    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值