Redis入门及在项目中的使用

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Redis入门及在项目中的使用

redis属于NoSql分类,它把数据都是缓存在内存中的,我们都知道内存的读写效率跟硬盘不是一个级别的,最后redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。既然用redis读取效率那么高,最后内容也会添加到磁盘那么我们就当然要使用它了。


一、redis的基本操作


redis是一个key-value存储系统。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sortedset–有序集合)和hash(哈希类型)五种数据类型,存储形式均为字符串。

启动redis

启动redis服务:[root@itheima32 src]# ./redis-server redis.conf

查看进程:[root@itheima32 bin]# ps aux|grep redis

root 1793 0.3 0.0 34992 1772 ? Ssl 10:29 0:00 ./redis-server *:6379

root 1797 0.0 0.0 5532 812 pts/0 S+ 10:29 0:00 grep redis

表示启动成功。

启动客户端:[root@itheima32 src]# ./redis-cli

127.0.0.1:6379>

其中6379表示本机的6379端口服务。

连接到该linux:ctrl+c退出,接着切换

[root@itheima32 bin]# ./redis-cli -h 192.168.25.128 -p 6379

192.168.25.128:6379>

这就切换成功了。接下来进行操作。


1.1、String类型


为了看的更直观,这里就直接展示操作内容。

存储:set key value

取值:get key

删除:del key

查看所有键:keys *

示例:

192.168.25.128:6379> set str1 123
OK
192.168.25.128:6379> set str2 abc
OK
192.168.25.128:6379> set str3 xixi
OK
192.168.25.128:6379> get str1
"123"
192.168.25.128:6379> get str2
"abc"
192.168.25.128:6379> get str3
"xixi"
192.168.25.128:6379> del str1
(integer) 1
192.168.25.128:6379> keys *
 1) "str2"
2) "str3"

增1:incr key

减1:decr key

注意, 虽然redis存储形式都是字符串,但是自增减的时候要求value必须能解析成数值类型,比如你的value是”1ad”那就不行。

示例:先添加键值对 str1 3,再自增就成了4

192.168.25.128:6379> set str1 3
OK
192.168.25.128:6379> incr str1
(integer) 4


1.2、Hash类型


相当于一个key对于一个map,map中还有key-value

存储:hset key field value

取值:hget key field

查看某个键对应的map里面的所有key:hkeys key

查看某个键对应的map里面的所有的value:hvals key

查看某个键的map:hgetall key

示例:

192.168.25.128:6379> hset hone field1 123
(integer) 1
192.168.25.128:6379> hset hone field2 abc
(integer) 1
192.168.25.128:6379> hset hone field3 haha
(integer) 1
192.168.25.128:6379> hget hone field1
"123"
192.168.25.128:6379> hget hone field2
"abc"
192.168.25.128:6379> hget hone field3
"haha"
192.168.25.128:6379> hkeys hone
1) "field1"
2) "field2"
3) "field3"
192.168.25.128:6379> hvals hone
1) "123"
2) "abc"
3) "haha"
192.168.25.128:6379> hgetall hone
1) "field1"
2) "123"
3) "field2"
4) "abc"
5) "field3"
6) "haha"


1.3、List类型


存储:push,分为lpush list v1 v2 v3 v4 …(左边添加),rpush list v1 v2 v3 v4 …(右边添加)

取值:pop,分为lpop lpop list(左边取,移除list最左边的值) ,rpop rpop list(右边取,移除list最右边的值)

查看list:lrange key 0 -1(0 -1表示查看所有)

存储,取值操作跟栈的存储,取值方法是一样的,而不是add,get,存储的值有序可以重复。用pop取值取完后该值就从list中移除了。

示例:

```
192.168.25.128:6379> lpush list1 1 2 3 4 5 6
(integer) 6
192.168.25.128:6379> rpush list1 a b c d e 
(integer) 11
192.168.25.128:6379> lrange list1 0 -1
 1) "6"
 2) "5"
 3) "4"
 4) "3"
 5) "2"
 6) "1"
 7) "a"
 8) "b"
 9) "c"
10) "d"
11) "e"
192.168.25.128:6379> lpop list1
"6"
192.168.25.128:6379> lrange list1 0 -1
 1) "5"
 2) "4"
 3) "3"
 4) "2"
 5) "1"
 6) "a"
 7) "b"
 8) "c"
 9) "d"
10) "e"
192.168.25.128:6379> rpop list1
"e"
192.168.25.128:6379> lrange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "a"
7) "b"
8) "c"
9) "d"

1.4、Set类型

set中的元素是无序不重复的,出现重复会覆盖

存储:sadd key v1 v2 v3 …

移除:srem key v

查看set集合: smembers key

另外还提供了差集,交集,并集操作

差集:sdiff seta setb(seta中有setb中没有的元素)

交集:sinter seta setb

并集:sunion seta setb

192.168.25.128:6379> sadd set a b a b c d
(integer) 4
192.168.25.128:6379> srem set a
(integer) 1
192.168.25.128:6379> smembers set
1) "d"
2) "b"
3) "c"
192.168.25.128:6379> sadd seta a b c d e
(integer) 5
192.168.25.128:6379> sadd setb c d e f g 
(integer) 5
192.168.25.128:6379> sdiff seta setb(差集,seta有setb没有)
1) "a"
2) "b"
192.168.25.128:6379> sdiff setb seta (差集,setb有seta没有)
1) "g"
2) "f"
192.168.25.128:6379> sinter seta setb(交集)
1) "d"
2) "e"
3) "c"
192.168.25.128:6379> sunion seta setb(并集)
1) "a"
2) "b"
3) "d"
4) "g"
5) "f"
6) "e"
7) "c"


1.5、SortedSet,有序Set


存储:存储的时候要求对set进行排序,需要对存储的每个value值进行打分,默认排序是分数由低到高。zadd key 分数1 v1 分数2 v2 分数3 v3…

取值:取指定的值 zrem key value

取所有的值(不包括分数):zrange key 0 -1,降序取值用zrevrange key 0 -1

取所有的值(带分数):zrange(zrevrange) key 0 -1 withscores

示例:

192.168.25.128:6379> zadd zset1 1 a 3 b 2 c 5 d(要求给定分数,从而达到排序效果,默认升序)
(integer) 4
192.168.25.128:6379> zrange zset1 0 -1
1) "a"
2) "c"
3) "b"
4) "d"
192.168.25.128:6379> zrem zset1 a 
(integer) 1
192.168.25.128:6379> zrange zset1 0 -1
1) "c"
2) "b"
3) "d"
192.168.25.128:6379> zrevrange zset1 0 -1(按分数降序排)
1) "d"
2) "b"
3) "c"
192.168.25.128:6379> zrevrange zset1 0 -1 withscores
1) "d"
2) "5"
3) "b"
4) "3"
5) "c"
6) "2"


1.6、key命令


由于redis是内存存储数据,所以不能够存储过大的数据量,所以存储在redis中的数据,在不再需要的时候应该清除掉。比如,用户买完东西下订单,生成的订单信息存储了在redis中,但是用户一直没支付那么存储在redis中的订单信息就应该清除掉,这个时候就可以通过设置redis的过期时间来完成,一旦达到了过期时间就清除该信息。

设置key的过期时间:expired key 过期时间(秒)

查看key的有效剩余时间:ttl key

清除key的过期时间,持久化该key:persist key

-1:表示持久化

-2: 表示该key不存在

示例:

192.168.25.128:6379> expire zone 60
(integer) 1
192.168.25.128:6379> ttl zone
(integer) 55
192.168.25.128:6379> ttl zone
(integer) 51
192.168.25.128:6379> ttl zone
(integer) 48
192.168.25.128:6379> ttl zone
(integer) 37
192.168.25.128:6379> ttl zone
(integer) 16
192.168.25.128:6379> ttl zone
(integer) -2  -->(该key已经不存在)
192.168.25.128:6379> expire sone 30
(integer) 1
192.168.25.128:6379> ttl sone
(integer) 22
192.168.25.128:6379> persist sone
(integer) 1
192.168.25.128:6379> ttl sone
(integer) -1  -->(该key是持久化的)

对与上面的基本操作,就我个人在案例中以及实习的真实项目中来说,至少得要掌握String类型,Hash类型以及key命令。


二、项目中使用redis


2.1、使用jedis操作redis测试


进行测试之前需要引入依赖

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.9.0</version>
</dependency>

测试:

@Test
    public void testJedis() throws Exception{
        //创建一个连接jedis对象,参数:host,port
        Jedis jedis = new Jedis("192.168.25.128", 6379);
        //直接使用jedis来操作redis,所有jedis的命令都对应一个方法
        jedis.set("test123", "my first jedis test");
        String s = jedis.get("test123");
        System.out.println(s);
        //关闭连接
        jedis.close();
    }
    输出结果:my first jedis test
    去客户端查看:
    192.168.25.128:6379> get test123
    "my first jedis test"

这里只测试了String类型,Jedis提供了与redis操作对应的方法来操作redis。

操作hash类型主要有:hset(…),hget(…),hdel(…),hexist(…)

key命令:persist(key),expire(key,seconds)

具体的根据提示来选择自己需要的。

测试,从连接池获取jedis:

@Test//连接
    public void testJedisPool() throws Exception{
        JedisPool jedisPool = new  JedisPool("192.168.25.128", 6379);
        //从连接池获得一个连接,就是一个jedis对象
        Jedis jedis = jedisPool.getResource();
        //操作redis
        String s = jedis.get("test123");
        System.out.println(s);
        //关闭连接,每次使用完毕后关闭连接,连接池回收资源
        jedis.close();
        //关闭连接池
        jedisPool.close();
    }

这个就跟从数据库连接池获取连接道理是一样的,需要连接的时候从连接池中取获取一个连接就行,使用完后就放回连接池,而不用重新去创建一个连接,这项技术能大大提高操作redis的性能。


2.2、使用JedisClient操作redis


测试的时候我们发现,每次都要自己创建关闭连接,频繁使用的话会显得很繁琐。所以我们可以一开始就定义好对应方法来帮我们关闭连接。使用的时候调用自己的方法即可。

接口如下:

public interface JedisClient {
    String set(String key, String value);
    String get(String key);
    Boolean exists(String key);
    Long expire(String key, int seconds);
    Long ttl(String key);
    Long incr(String key);
    Long hset(String key, String field, String value);
    String hget(String key, String field);
    Long hdel(String key, String... field);
    Boolean hexists(String key, String field);
    List<String> hvals(String key);
    Long del(String key);
}

这里定义的方法主要是针对String类型,Hash类型,key命令。

比如String类型,Hash类型的存储、获取、删除、是否存在指定key,设置过期时间,自增,自间,有效时间等。

实现类如下:

public class JedisClientPool implements JedisClient {
    private JedisPool jedisPool;
    public JedisPool getJedisPool() {
        return jedisPool;
    }
    public void setJedisPool(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }
    public String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.set(key, value);
        jedis.close();
        return result;
    }
    public String get(String key) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.get(key);
        jedis.close();
        return result;
    }
    public Boolean exists(String key) {
        Jedis jedis = jedisPool.getResource();
        Boolean result = jedis.exists(key);
        jedis.close();
        return result;
    }
    public Long expire(String key, int seconds) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.expire(key, seconds);
        jedis.close();
        return result;
    }
    public Long ttl(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.ttl(key);
        jedis.close();
        return result;
    }
    public Long incr(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.incr(key);
        jedis.close();
        return result;
    }
    public Long hset(String key, String field, String value) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hset(key, field, value);
        jedis.close();
        return result;
    }
    public String hget(String key, String field) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.hget(key, field);
        jedis.close();
        return result;
    }
    public Long hdel(String key, String... field) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hdel(key, field);
        jedis.close();
        return result;
    }
    public Boolean hexists(String key, String field) {
        Jedis jedis = jedisPool.getResource();
        Boolean result = jedis.hexists(key, field);
        jedis.close();
        return result;
    }
    public List<String> hvals(String key) {
        Jedis jedis = jedisPool.getResource();
        List<String> result = jedis.hvals(key);
        jedis.close();
        return result;
    }
    public Long del(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.del(key);
        jedis.close();
        return result;
    }
}

其实这些方法主要还是调用了jedis的方法,主要是帮我们创建、关闭了连接然后进行封装,从而在项目中使用可以简化操作。


2.3、从Spring容器中获取JedisClient


在案例中,JedisClient是与Spring整合的。不然每次都要自己创建JedisClient对象,使用Spring那么就不用我们自己创建对象了。

JedisClient与spring整合:applicationContext-redis.xml

配置jedis连接池
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="host" value="192.168.25.128"/>
        <constructor-arg name="port" value="6379"/>
    </bean>
<!-- 连接-->
    <bean class="com.neusoft.util.JedisClientPool">
        <property name="jedisPool" ref="jedisPool"/>
    </bean>

这样初始化Spring容器的时候就会创建JedisClient了

测试:

public void testJedisClient() throws Exception{
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-redis.xml");
        //从容器中拿到JedisClient对象
        JedisClient jc = ac.getBean(JedisClient.class);
        jc.set("mytest", "jedisClient");
        String s = jc.get("mytest");
        System.out.println(s);  
    }
    输出:jedisClient

到这里就可以大胆的在项目中使用JedisClient来操作redis了。


2.4、实现redis在文章案例中进行缓存

2.4.1、在文章详情中使用redis


点击某篇文章会进入到文章详情页。这里也使用了redis,比如某篇文章很热门,那么单位时间的浏览量就会很高,对于这种情况我们可以将文章信息添加到redis中。

点击文章的时候会根据文章id去redis中查询是否存在该文章信息,有的话直接响应,如果没有那么就去查数据库,查出来的数据存到redis中再做响应。

但文章信息不能一直在redis中存放,文章过多的话非常耗费redis的存储空间,所以需要设置一下过期时间,如果这段时间该文章没人访问的话就应该将该文章信息从redis中清除来释放空间,如果有人访问的话那么就重新设置回原来的过期时间。

@Service
public class ArticleService implements IArticleService {
    @Autowired
    ArticleMapper articleMapper;
    @Autowired
    CommentMapper commentMapper;
    @Autowired
    private SolrServer solrServer;
    @Autowired
    private JedisClient jedisClient;
    @Value("${REDIS_ITEM_PRE}")
    private String REDIS_ITEM_PRE;
    @Value("${ITEM_CACHE_EXPIRE}")
    private Integer ITEM_CACHE_EXPIRE;
    @Override
    public Article getArticleByID(int aid) {
        try {
            String string = jedisClient.get(REDIS_ITEM_PRE+":"+aid+":BASE");
            if(string !=null && !string.isEmpty()){
//设置过期时间
                jedisClient.expire(REDIS_ITEM_PRE+":"+aid+":BASE", ITEM_CACHE_EXPIRE);
                Article tbItem = JSON.parseObject(string,new TypeReference<Article>() {});
                return tbItem;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Article article = articleMapper.getArticleByID(aid);
        if(article != null){
            //把结果添加到缓存
            try {
                jedisClient.set(REDIS_ITEM_PRE+":"+aid+":BASE", JSON.toJSONString(article));
                //设置过期时间
                jedisClient.expire(REDIS_ITEM_PRE+":"+aid+":BASE", ITEM_CACHE_EXPIRE);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return article;
        }else{
            return null;
        }
    }
}

applicationContext-redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd ">
        <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
                <constructor-arg name="host" value="192.168.47.141"/>
                <constructor-arg name="port" value="6379"/>
        </bean>
        <bean class="com.neusoft.util.JedisClientPool">
                <property name="jedisPool" ref="jedisPool"/>
        </bean>
        <context:property-placeholder location="classpath:app.properties"/>
</beans>

这里使用的是String类型,写成 前缀:d:后缀,这种形式在桌面版redis客户端中文件目录会有层次结构。


Redis实现缓存同步


考虑这么个问题,如果在后台我们修改或删除了文章信息,这就存在信息不同步问题了。这里解决的办法是,每次修改或删除了文章,那么就需要清空redis中的信息。当下次访问首页的时候会去数据库中查询最新的内容信息,存放到redis中,从而实现了缓存同步,代码如下。

jedisClient.del(REDIS_ITEM_PRE+":"+aid+":BASE");


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
NoSQL 安全 测试技术
Redis游戏积分排行榜项目中通义灵码的应用实战
Redis游戏积分排行榜项目中通义灵码的应用实战
57 4
|
18天前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
98 26
|
1月前
|
NoSQL Java API
springboot项目Redis统计在线用户
通过本文的介绍,您可以在Spring Boot项目中使用Redis实现在线用户统计。通过合理配置Redis和实现用户登录、注销及统计逻辑,您可以高效地管理在线用户。希望本文的详细解释和代码示例能帮助您在实际项目中成功应用这一技术。
41 4
|
2月前
|
缓存 NoSQL Java
springboot的缓存和redis缓存,入门级别教程
本文介绍了Spring Boot中的缓存机制,包括使用默认的JVM缓存和集成Redis缓存,以及如何配置和使用缓存来提高应用程序性能。
130 1
springboot的缓存和redis缓存,入门级别教程
|
2月前
|
存储 消息中间件 NoSQL
Redis 入门 - C#.NET Core客户端库六种选择
Redis 入门 - C#.NET Core客户端库六种选择
71 8
|
4月前
|
SQL 存储 NoSQL
Redis6入门到实战------ 一、NoSQL数据库简介
这篇文章是关于NoSQL数据库的简介,讨论了技术发展、NoSQL数据库的概念、适用场景、不适用场景,以及常见的非关系型数据库。文章还提到了Web1.0到Web2.0时代的技术演进,以及解决CPU、内存和IO压力的方法,并对比了行式存储和列式存储数据库的特点。
Redis6入门到实战------ 一、NoSQL数据库简介
|
4月前
|
NoSQL 算法 安全
Redis6入门到实战------ 四、Redis配置文件介绍
这篇文章详细介绍了Redis配置文件中的各种设置,包括单位定义、包含配置、网络配置、守护进程设置、日志记录、密码安全、客户端连接限制以及内存使用策略等。
Redis6入门到实战------ 四、Redis配置文件介绍
|
4月前
|
NoSQL Redis 数据安全/隐私保护
Redis6入门到实战------ 二、Redis安装
这篇文章详细介绍了Redis 6的安装过程,包括下载、解压、编译、安装、配置以及启动Redis服务器的步骤。还涵盖了如何设置Redis以在后台运行,如何为Redis设置密码保护,以及如何配置Redis服务以实现开机自启动。
Redis6入门到实战------ 二、Redis安装
|
4月前
|
NoSQL Java Redis
Redis6入门到实战------思维导图+章节目录
这篇文章提供了Redis 6从入门到实战的全面学习资料,包括思维导图和各章节目录,涵盖了NoSQL数据库、Redis安装配置、数据类型、事务、持久化、主从复制、集群等核心知识点。
Redis6入门到实战------思维导图+章节目录
|
4月前
|
NoSQL 安全 Java
Redis6入门到实战------ 三、常用五大数据类型(字符串 String)
这篇文章深入探讨了Redis中的String数据类型,包括键操作的命令、String类型的命令使用,以及String在Redis中的内部数据结构实现。
Redis6入门到实战------ 三、常用五大数据类型(字符串 String)