关于redis,jedis,Spring-data-redis,这一篇文章就完了

NOSQL

什么是NOSQLNOSQL

NoSQL(NoSQL=Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库。

解决什么问题

  • web程序不再仅仅专注在功能上,同时也在追求性能;
  • 对数据库高并发读写的需求(High performance),现在数据库并发负载非常高,往往要达到每秒上万次读写请求,关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了;
  • 对海量数据的高效率存储和访问的需求(Huge Storage),对于关系数据库来说,在一张2.5亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的;
  • 对数据库的高可扩展性和高可用性的需求(High Scalability && High Availability-),对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移;

主流的NOSQL产品

  • 主流产品:redis,mongoDB,CouchDB,riak等
  • 键值(Key-Value)存储数据库—redis:主要使用内存,有两种持久化方案(RDB和AOF),速度非常快,一般做分布式缓存使用;
  • 文档型数据库-MongoDB:主要使用硬盘存储,所以不会担心数据丢失,速度介于redis和传统数据库之间,但是mongodb更擅长存储大文本数据,以及一些非结构化数据,mongodb比redis的数据类型更加丰富,例如:存储小说网站的小说,存储电商网站的评论等这些数据。

Redis

redis概述

Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。

redis的应用场景

  • 缓存(数据查询、短连接、新闻内容、商品内容等等);
  • 聊天室的在线好友列表;
  • 任务队列。(秒杀、抢购、12306等等);
  • 应用排行榜;
  • 网站访问统计;
  • 数据过期处理(可以精确到毫秒);
  • 分布式集群架构中的session分离

业务流程

  • 获取数据的时候先从redis中获取,如果获取到数据则直接返回,就不用访问数据库了;
  • 如果获取不到数据,可以从数据库中查询,查询到后放入redis中一份,下回就可以直接从redis中查询到;

这样大大降低了数据库的高并发访问压力。

持久化方案

  • RDB(默认) 分时持久化:可以在配置文件中设定,多长时间持久化一次,持久化次数少也就是操作硬盘的次数少,速度快.但是如果在没有完成持久化前,如果服务器断电,则内存中没有持久化的数据会丢失;
  • AOF 实时持久化:每次向redis中做增删改操作, 都会将数据持久化到硬盘上,数据可靠性高,不会丢失,但是速度慢。

redis安装

windows

  • window版的安装及其简单,
  • 解压Redis压缩包完成即安装完毕,
  • 双击Redis目录中redis-server.exe可以启动redis服务,Redis服务占用的端口是6379,
  • 关闭Redis的控制台窗口就可以关闭Redis服务

linux

  • 将redis在Linux的安装包上传到/usr/local当中,
  • 解压:tar -xvf redis-4.0.9.tar.gz
  • 编译安装:
    1. 进入到redis目录(cd /usr/local/redis-4.0.9/),
    2. make
    3. make install PREFIX='/usr/local/redis-4.0.9/6379'
  • 启动:/usr/local/redis-4.0.9/6379/bin/redis-server
  • 修改配置文件:
    1. /usr/local/redis-4.0.9/目录下的配置文件复制一份到6379目录下(cp redis.conf /usr/local/redis-4.0.9/6379/bin/
    2. 修改配置文件:
      1. #bind 127.0.0.1 # 将这行代码注释,监听所有的ip地址,外网可以访问
      2. protected-mode no # 把yes改成no,允许外网访问
      3. daemonize yes #no改成yes,后台运行
    3. 重新启动:./redis-server redis.conf
    4. 查看进程:ps -ef|grep redis

Redis的数据类型

  • redis是一种高级的key-value的存储系统,其中value支持五种数据类型。
  • Redis的5种数据类型:
    1. 字符串(String)
    2. 哈希(hash)
    3. 字符串列表(list)
    4. 字符串集合(set)
    5. 序字符串集合(sorted set)
  • key的定义注意点:
    1. key不要太长,最好不要操作1024个字节,这不仅会消耗内存还会降低查找效率;
    2. key不要太短,如果太短会降低key的可读性
    3. 在项目中,key最好有一个统一的命名规范

基本操作

  • 字符串类型string
    1. 概述:设定key持有指定的字符串value,如果该key存在则进行覆盖操作。总是返回”OK”
    2. 操作:
      1. set key value:set name it
      2. get key:get it,获取key的value。如果与该key关联的value不是String类型,redis将返回错误信息;
      3. del key:del it
      4. 示例:关于redis,jedis,Spring-data-redis,这一篇文章就完了_第1张图片
  • 哈希类型hash
    1. 概述:Redis中的Hash类型可以看成具有String Key和String Value的map容器,所以该类型非常适合于存储值对象的信息;
    2. 操作:
      1. hset key field value:为指定的key设定field/value对(键值对),
        hset myhash name it——存入hash类型值myhash存的值为name:it
      2. hget key field返回指定的key中的field的值
      3. hdel key field [field … ]可以删除一个或多个字段,返回值是被删除的字段个数
      4. hgetall key:可以获取该键的所有数据
      5. 示例:关于redis,jedis,Spring-data-redis,这一篇文章就完了_第2张图片
  • 列表类型list
    1. 概述:在Redis中,List类型是按照插入顺序排序的字符串链表,和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素,在插入时,如果该键并不存在,Redis将为该键创建一个新的链表,与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除,List中可以包含的最大元素数量是4294967295。
    2. 操作:
      1. lpush key values[value1 value2…]:lpush mylist a b c——在指定的key所关联的list的头部插入所有的values,如果该key不存在,该命令在插入的之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据,插入成功,返回元素的个数。
      2. lpop key:lpop mylist返回并弹出指定的key关联的链表中的第一个元素,即头部元素,如果该key不存在,返回nil;若key存在,则返回链表的头部元素。
      3. rpop key从尾部弹出元素,与lpop key相反。
      4. lrange key遍历该键的所有数据
  1. lrange key  0 2返回0 1 2
  2. lrange key  0 -1返回所有
  1. 示例关于redis,jedis,Spring-data-redis,这一篇文章就完了_第3张图片
  • 集合类型set
    1. 概述:在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作,Set集合中不允许出现重复的元素。
    2. 操作:
      1. sadd key values[value1、value2…]:sadd myset a b c:向set中添加数据,如果该key的值已有则不会重复添加
      2. smembers key:smembers myset:获取set中所有的成员
      3. srem key members[member1、member2…]:srem myset a b:删除set中指定的成员
  • 有序集合类型sortset
    1. 概述:在redis中,可以保证不重复的元素,仍然可以进行排序。
    2. 操作:
      1. zadd key values[value1、value2…]:zadd mysort 5 zs 10 lisi 7 wc 8 xk
      2. zrange key 索引 索引:zrange mysort 0 -1
      3. zrem key  value:zrem mysort lisi

Redis的通用命令

  • keys pattern:获取所有与pattern匹配的key,返回所有与该key匹配的keys,*表示任意一个或多个字符,?表示任意一个字符。
  • del key1 key2…删除指定的key
  • exists key判断该key是否存在,1代表存在,0代表不存在
  • type key获取指定key的类型。该命令将以字符串的格式返回,返回的字符串为string、list、set、hash,如果key不存在返回none

Redis的持久化

  • 概述:Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化,Redis支持两种方式的持久化,可以单独使用其中一种或将二者结合使用。
    1. 一种是RDB方式,一种是AOF方式:该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
      1. RDB持久化(默认支持,无需配置):该机制将以日志的形式记录服务器所处理的每一个写操作。
      2. AOF持久化:在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
      3. 无持久化:我们可以通过配置的方式禁用Redis服务器的持久化功能,这样我们就可以将Redis视为一个功能加强版的memcached了
  • redis可以同时使用RDB和AOF。
  • RDB持久化机制:
    1. RDB持久化机制优点:一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的
    2. RDB持久化机制缺点:如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
    3. 快照触发条件:
      1. 客户端执行命令save和bgsave会生成快照;
      2. 根据配置文件save m n规则进行自动快照;
      3. 主从复制时,从库全量复制同步主库数据,此时主库会执行bgsave命令进行快照;
      4. 客户端执行数据库清空命令FLUSHALL时候,触发快照;
      5. 客户端执行shutdown关闭redis时,触发快照;
  1. RDB持久化机制的配置:
      1. save m n
        1. 配置快照(rdb)促发规则,格式:save
        2. save 900 1  900秒内至少有1个key被改变则做一次快照
        3. save 300 10  300秒内至少有10个key被改变则做一次快照
        4. save 60 10000  60秒内至少有10000个key被改变则做一次快照
        5. #关闭该规则使用save “ ”
      2. dbfilename  dump.rdbrdb持久化存储数据库文件名,默认为dump.rdb
      3. stop-write-on-bgsave-error yesyes代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no表明忽略错误继续写文件。
      4. rdbchecksum yes在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。
      5. dir "./"数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限
      6. rdbcompression yes: 是否开启RDB文件压缩,该功能可以节约磁盘空间
  • AOF持久化机制:
  1. AOF概述:当redis存储非临时数据时,为了降低redis故障而引起的数据丢失,redis提供了AOF(Append Only File)持久化,从单词意思讲,将命令追加到文件。AOF可以将Redis执行的每一条写命令追加到磁盘文件(appendonly.aof)中, 在redis启动时候优先选择从AOF文件恢复数据。由于每一次的写操作,redis都会记录到文件中,所以开启AOF持久化会对性能有一定的影响, AOF持久化数据丢失更少,其消耗内存更少(RDB方式执行bgsve会有内存拷贝)
  2. 开启AOF持久化: 默认情况下,redis是关闭了AOF持久化,开启AOF通过配置appendonly为yes开启, 将appendonly修改为yes,开启aof持久化机制,默认会在目录下产生一个appendonly.aof文件, 我们修改配置文件或者在命令行直接使用config set修改,在用config rewrite同步到配置文件。通过客户端修改好处是不用重启redis,AOF持久化直接生效
    1. config get appendonly: 查询配置状态
    2. config set appendonly yes: 修改配置
    3. config rewrite: 写入到redis.conf中
  3. 配置: appendfsync
    1. always: 每执行一次更新命令,持久化一次
    2. everysec: 每秒钟持久化一次
    3. no: 不持久化
  • RDB-AOF混合持久化

通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,默认是禁用的,可通过config set修改。

jedis的介绍

使用Jedis操作redis需要导入jar包如下:(Jedis相当于redis的连接池)

 

  • jedis常用API
  1. new Jedis(host, port)创建jedis对象,参数host是redis服务器地址,参数port是redis服务端口
  2. set(key,value)设置字符串类型的数据
  3. get(key)获得字符串类型的数据
  4. hset(key,field,value):设置哈希类型的数据
  5. hget(key,field)获得哈希类型的数据
  6. lpush(key,values)设置列表类型的数据
  7. lpop(key)列表左面弹栈
  8. rpop(key)列表右面弹栈
  9. del(key)删除指定的key
  • jedis的基本操作:

关于redis,jedis,Spring-data-redis,这一篇文章就完了_第4张图片

  • jedis连接池的基本概念:
    1. jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的池化技术
    2. 示例代码: 关于redis,jedis,Spring-data-redis,这一篇文章就完了_第5张图片

Spring-data-redis

  • Spring-data-redis概述:
    1. Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis,  JRedis, and RJC)进行了高度封装,RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅
  • Spring-data-redis功能:
    1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
    2. 针对jedis客户端中大量api进行了归类封装
      1. SetOperations:set类型数据操作
      2. ZSetOperations:zset类型数据操作
      3. HashOperations:针对map类型的数据操作
      4. ListOperations:针对list类型的数据操作
      5. ValueOperations:简单K-V操作
  • Spring-data-redis入门程序:
    1. 1.构建Maven工程  SpringDataRedisDemo   jar工程
    2. 2.引入Spring/Jedis和SpringDataRedis依赖:




junit

junit

4.12





org.springframework

spring-context

5.1.7.RELEASE





org.springframework

spring-beans

5.1.7.RELEASE





org.springframework

spring-context-support

5.1.7.RELEASE





org.springframework

spring-test

5.1.7.RELEASE







redis.clients

jedis

2.8.1





org.springframework.data

spring-data-redis

1.7.2.RELEASE



  1. 3.在src/main/resources建立redis-config.properties
redis.host=192.168.1.9

redis.port=6379

redis.pass=

redis.database=0

redis.maxIdle=300

redis.maxWait=3000

redis.testOnBorrow=true
  1. 4.在src/main/resources创建applicationContext-redis.xml





    

    

    

        

        

        

    

    


    

        

    

  1. 5.建立TestString测试字符串操作方法
@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})

public class TestString {

    @Autowired

    private RedisTemplate redisTemplate;

    @Test

    public void testSet() {

        redisTemplate.boundValueOps("name").set("it");

    }

    @Test

    public void testGet() {

        String name = (String) redisTemplate.boundValueOps("name").get();

        System.out.println("name=" + name);

    }

    @Test

    public void testDelete() {

        redisTemplate.delete("name");

    }

}
  1. 6.建立TestList测试List操作方法
@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})

public class TestList {

    @Autowired

    private RedisTemplate redisTemplate;

    @Test

    public void testLpush() {

        redisTemplate.boundListOps("myListKey").leftPush("001");

        redisTemplate.boundListOps("myListKey").leftPush("002");

        redisTemplate.boundListOps("myListKey").leftPush("003");

        redisTemplate.boundListOps("myListKey").leftPush("004");

    }

    @Test

    public void testRpush() {

        redisTemplate.boundListOps("myListKey").rightPush("001");

        redisTemplate.boundListOps("myListKey").rightPush("002");

        redisTemplate.boundListOps("myListKey").rightPush("003");

        redisTemplate.boundListOps("myListKey").rightPush("004");

    }

    @Test

    public void testRange() {

        List myListKey = redisTemplate.boundListOps("myListKey").range(0, -1);

        for (String s : myListKey) {

            System.out.println("value=" + s);

        }

    }


    @Test

    public void testDelete() {

        redisTemplate.delete("myListKey");

    }

}
  1. 7.建立TestHash测试hash
@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})

public class TestHash {


    @Autowired

    private RedisTemplate redisTemplate;

    @Test

    public void testPut() {

        redisTemplate.boundHashOps("keyname1").put("name", "zs");

        redisTemplate.boundHashOps("keyname1").put("age", "20");

        redisTemplate.boundHashOps("keyname1").put("phone", "121");

        redisTemplate.boundHashOps("keyname1").put("email", "[email protected]");

    }


    @Test

    public void testGetOne() {

        String name = (String)redisTemplate.boundHashOps("keyname1").get("name");

        System.out.println("name =" + name);

    }


    @Test

    public void testGetAll() {

        //获取所有的entries

        Map testHash = (Map)redisTemplate.boundHashOps("keyname1").entries();

        Set> entries = testHash.entrySet();

        for (Map.Entry entry : entries) {

            System.out.println("key=" + entry.getKey());

            System.out.println("value=" + entry.getValue());

        }

    }


    @Test

    public void testDeleteOne() {

        redisTemplate.boundHashOps("keyname1").delete("name");

    }


    @Test

    public void testDeleteAll() {

        redisTemplate.delete("keyname1");

    }

}

 

redis设置密码

进入redis命令模式(/usr/local/redis-4.0.9/6379/bin/redis-cli)

config set requirepass admin

auth admin

实例:使用redis缓存广告

  • 1、添加redis依赖


        

            com.fasterxml.jackson.core

            jackson-databind

            2.9.4

        

        

            com.fasterxml.jackson.core

            jackson-annotations

            2.9.4

        

        

            com.fasterxml.jackson.core

            jackson-core

            2.9.4





redis.clients

jedis





org.springframework.data

spring-data-redis

  • 2、添加redis配置文件和属性文件
    1. redis-config.properties
redis.host=192.168.1.9

redis.port=6379

redis.pass=admin

redis.database=0

redis.maxIdle=300

redis.maxWait=3000

redis.testOnBorrow=true
    1. applicationContext-redis.xml





    

    

    

        

        

        

    

    


    

        

    

  • 使用redis过程分析
    1. 获取数据的时候先从redis中获取,如果获取到数据则直接返回,就不用访问数据库了,
    2. 如果获取不到数据,可以从数据库中查询,查询到后放入redis中一份,下回就可以直接从redis中查询到,

这样大大降低了数据库的高并发访问压力。

  • 查询分类广告方法
    1. 创建工具类统一管理 redis键

关于redis,jedis,Spring-data-redis,这一篇文章就完了_第6张图片

    1. redis数据存在结构:field为分类名称   value为分类下的广告

关于redis,jedis,Spring-data-redis,这一篇文章就完了_第7张图片

    1. 查询、修改、删除、更新分类广告服务层方法:
@Transactional

@Service

public class ContentServiceImpl implements ContentService {

@Autowired

private ContentDao contentDao;

@Autowired

private RedisTemplate redisTemplate;

@Override

public PageResult findPage(Content content, Integer page, Integer rows) {

         PageHelper.startPage(page, rows);

         ContentQuery query = new ContentQuery();

         ContentQuery.Criteria criteria = query.createCriteria();

         if (content != null) {

                  if (content.getTitle() != null && !"".equals(content.getTitle())) {

                           criteria.andTitleLike(content.getTitle()+"%");

                  }

         }

         Page contentList = (Page)contentDao.selectByExample(query);

         return new PageResult(contentList.getTotal(), contentList.getResult());

}


@Override

public void add(Content content) {

         /**

          * 1. 将新广告添加到数据库中

          */

         contentDao.insertSelective(content);

         /**

          * 2. 根据分类id, 到redis中删除对应分类的广告集合数据

          */

redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).delete(content.getCategoryId());

}



@Override

public Content findOne(Long id) {

         return contentDao.selectByPrimaryKey(id);

}


@Override

public void update(Content content) {

         /**

          * 1. 根据广告id, 到数据库中查询原来的广告对象

          */

         Content oldContent = contentDao.selectByPrimaryKey(content.getId());

         /**

          * 2. 根据原来的广告对象中的分类id, 到redis中删除对应的广告集合数据

          */

redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).delete(oldContent.getCategoryId());

         /**

          * 3. 根据传入的最新的广告对象中的分类id, 删除redis中对应的广告集合数据

          */

redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).delete(content.getCategoryId());

         /**

          * 4. 将新的广告对象更新到数据库中

          */

         contentDao.updateByPrimaryKeySelective(content);

}


@Override

public void delete(Long[] ids) {

         if (ids != null) {

                  for (Long id : ids) {

                           /**

                            * 1. 根据广告id, 到数据库中查询广告对象

                            */

                           Content content = contentDao.selectByPrimaryKey(id);

                           /**

                            * 2. 根据广告对象中的分类id, 删除redis中对应的广告集合数据

                            */

                  redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).delete(content.getCategoryId());

                           /**

                            * 3. 根据广告id删除数据库中的广告数据

                            */

                           contentDao.deleteByPrimaryKey(id);

                  }

         }

}


@Override

public List findByCategoryId(long categoryId) {

         ContentQuery query = new ContentQuery();

         ContentQuery.Criteria criteria = query.createCriteria();

         criteria.andCategoryIdEqualTo(categoryId);

         List list = contentDao.selectByExample(query);

         return list;

}


@Override

public List findByCategoryIdFromRedis(Long categoryId) {

         /**

          * 1. 首先根据分类id到redis中获取数据

          */

         List contentList = (List)redisTemplate

                           .boundHashOps(Constants.CONTENT_LIST_REDIS)

                           .get(categoryId);

         /**

          * 2. 如果redis中没有数据则到数据库中获取数据

          */

         if (contentList == null) {

                  /**

                   * 3. 如果数据库中获取到数据, 则放入redis中一份

                   */

                  contentList = findByCategoryId(categoryId);

         redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).put(categoryId, contentList);

         }

         return contentList;

}


}
    1. 控制层从redis中调用服务层取出数据
@RestController

@RequestMapping("/content")

public class ContentController {

    @Reference

    private ContentService contentService;


    @RequestMapping("/findByCategoryId")

    public List findByCategoryId(long categoryId){

             return contentService.findByCategoryIdFromRedis(categoryId);

    }

}

 

关于redis,jedis,Spring-data-redis,这一篇文章就完了_第8张图片关于redis,jedis,Spring-data-redis,这一篇文章就完了_第9张图片关于redis,jedis,Spring-data-redis,这一篇文章就完了_第10张图片

 

你可能感兴趣的:(redis,分布式)