一、说在前面的话
前面几节我们主要对该项目的后端进行了增删改查,但是所有的数据都是存放在数据库中,这样的话数据库的压力显而易见是很大的,因此本节学习nosql的缓存,也就是redis的使用,在使用之前,我们来想一想为什么要用redis、redis的内存是否有限制,redis的存储方式。那么让我们带着这些问题去学习redis。
Redis服务器的搭建和使用。
二、redis
1、redis的安装
Redis是c语言开发的。
安装redis需要c语言的编译环境。如果没有gcc需要在线安装。(上一节nginx也是c开发的,因此也安装了c++编译环境)
yum install gcc-c++
安装步骤:
第一步:redis的源码包上传到linux系统。
第二步:解压缩redis。
第三步:编译。进入redis源码目录。make
第四步:安装。make install PREFIX=/usr/local/redis
PREFIX参数指定redis的安装目录。一般软件安装到/usr目录下
2、redis的启动
前端启动:在redis的安装目录下直接启动redis-server(一般不采取此方法)
[root@localhost bin]# ./redis-server
后台启动:
把/root/redis-3.0.0/redis.conf复制到/usr/local/redis/bin目录下
[root@localhost redis-3.0.0]# ==cp redis.conf /usr/local/redis/bin/ == (为了启动的后面直接跟配置文件)
修改配置文件:daemonize: yes
daemonize:yes:
redis采用的是单进程多线程的模式。当redis.conf中选项daemonize设置成yes时,代表开启守护进程模式。在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项pidfile设置的文件中,此时redis将一直运行,除非手动kill该进程。
daemonize:no:
当daemonize选项设置成no时,当前界面将进入redis的命令行界面,exit强制退出或者关闭连接工具(putty,xshell等)都会导致redis进程退出。
老版本默认是no,新版本现在默认是yes。
最后我们启动的时候在后面跟上配置文件即可
[root@localhost bin]# ./redis-server redis.conf
查看redis进程:
[root@localhost bin]# ps aux|grep redis
root 5190 0.1 0.3 33936 1712 ? Ssl 18:23 0:00./redis-server :6379
root 5196 0.0 0.1 4356 728 pts/0 S+ 18:24 0:00 grep redis
3、redis的命令行连接和图形化连接
a、命令连接:
[root@localhost bin]# ./redis-cli
默认连接localhost运行在6379端口的redis服务。
[root@localhost bin]# ./redis-cli -h 192.168.25.153 -p 6379
-h:连接的服务器的地址(host)
-p:服务的端口号(port)
b、图形化连接
使用软件RedisDesktopManager进行连接redis
c、redis的存储数据类型
redis有5中存储数据类型,每一种类型的数据都以String的形式进行保存到redis缓存中的。
——1、String:key-value(做缓存、可以使用ttl过期时间,因此经常被用到用户登录、商品缓存(使用TTL有效的使热门数据存放到redis缓存中,从而避免内存浪费的可能。)、订单提交等模块中)故经常使用。
get、set、
incr:加一(生成id)
Decr:减一
当然只有value为数值才可以增减,若为字母,则报错
接下来看看图形化界面是什么样的?
——2、Hash:key-fields-values(做缓存)也经常使用(这里因为hash没法使用ttl过期,所以一般用在用户的购物车等模块中。)
相当于一个key对于一个map,map中还有key-value
使用hash对key进行归类。
Hset:向hash中添加内容
Hget:从hash中取内容
在图形化界面我们再看看什么样的
3、list 有顺序可重复
lrange list1 0 -1 代表输出list1集合,从第0个开始,一直到最后一个(0代表第一个、-1代表最后一个)。
192.168.25.153:6379> lpush list1 a b c d (integer) 4 192.168.25.153:6379> lrange list1 0 -1 1) "d" 2) "c" 3) "b" 4) "a" 192.168.25.153:6379> rpush list1 1 2 3 4 (integer) 8 192.168.25.153:6379> lrange list1 0 -1 1) "d" 2) "c" 3) "b" 4) "a" 5) "1" 6) "2" 7) "3" 8) "4" 192.168.25.153:6379> 192.168.25.153:6379> lpop list1 "d" 192.168.25.153:6379> lrange list1 0 -1 1) "c" 2) "b" 3) "a" 4) "1" 5) "2" 6) "3" 7) "4" 192.168.25.153:6379> rpop list1 "4" 192.168.25.153:6379> lrange list1 0 -1 1) "c" 2) "b" 3) "a" 4) "1" 5) "2" 6) "3"
4、set 元素无顺序,不能重复
192.168.25.153:6379> sadd set1 a b c c c d (integer) 4 192.168.25.153:6379> smembers set1 1) "b" 2) "c" 3) "d" 4) "a" 192.168.25.153:6379> srem set1 a (integer) 1 192.168.25.153:6379> smembers set1 1) "b" 2) "c" 3) "d"
5、SortedSet(zset):有顺序,不能重复
192.168.25.153:6379> zadd zset1 2 a 5 b 1 c 6 d (integer) 4 192.168.25.153:6379> zrange zset1 0 -1 1) "c" 2) "a" 3) "b" 4) "d" 192.168.25.153:6379> zrem zset1 a (integer) 1 192.168.25.153:6379> zrange zset1 0 -1 1) "c" 2) "b" 3) "d" 192.168.25.153:6379> zrevrange zset1 0 -1 1) "d" 2) "b" 3) "c" 192.168.25.153:6379> zrange zset1 0 -1 withscores 1) "c" 2) "1" 3) "b" 4) "5" 5) "d" 6) "6" 192.168.25.153:6379> zrevrange zset1 0 -1 withscores 1) "d" 2) "6" 3) "b" 4) "5" 5) "c" 6) "1"
d、key命令(不可以对hash的key值设置过期时间)
设置key的过期时间。
Expire key second:设置key的过期时间
Ttl key:查看key的有效期
Persist key:清除key的过期时间。Key持久化。
192.168.25.153:6379> expire Hello 100
(integer) 1
192.168.25.153:6379> ttl Hello
(integer) 77
只能对整个hash设置过期时间。
消除key的过期时间:
PERSIST hstr
6、redis在项目中的使用
我们在项目需要使用到redis,那么我们该如何去连接呢,redis给我们提供了连接的jar包jedis,我们需要把它引入到其中,添加依赖。建议添加到服务层中。
由于redis含有单机版和集群版(集群版搭建链接),因此这里创建了一个接口,把单机版和集群版都实现这个接口(JedisClient ),若我们使用单机版,则在配置文件中配置单机版的设置,反之配置集群版的设置。单机版的实现类和集群版的实现类内容不一样。但是我们都是基于接口进行操作的。这样的话开发和上线就不需要更换代码了,只需要将配置文件单机版和集群版修改即可。
JedisClient 接口:
package cn.tsu.e3mall.jedis; import java.util.List; 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); }
JedisClientPool(单机版)
单机版的获取Pool后,需要getResource,然后就可以得到jedis,就可以操作set,get命令。
package cn.tsu.e3mall.jedis; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; public class JedisClientPool implements JedisClient { private JedisPool jedisPool; public JedisPool getJedisPool() { return jedisPool; } public void setJedisPool(JedisPool jedisPool) { this.jedisPool = jedisPool; } @Override public String set(String key, String value) { Jedis jedis = jedisPool.getResource(); String result = jedis.set(key, value); jedis.close(); return result; } @Override public String get(String key) { Jedis jedis = jedisPool.getResource(); String result = jedis.get(key); jedis.close(); return result; } @Override public Boolean exists(String key) { Jedis jedis = jedisPool.getResource(); Boolean result = jedis.exists(key); jedis.close(); return result; } @Override public Long expire(String key, int seconds) { Jedis jedis = jedisPool.getResource(); Long result = jedis.expire(key, seconds); jedis.close(); return result; } @Override public Long ttl(String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.ttl(key); jedis.close(); return result; } @Override public Long incr(String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.incr(key); jedis.close(); return result; } @Override public Long hset(String key, String field, String value) { Jedis jedis = jedisPool.getResource(); Long result = jedis.hset(key, field, value); jedis.close(); return result; } @Override public String hget(String key, String field) { Jedis jedis = jedisPool.getResource(); String result = jedis.hget(key, field); jedis.close(); return result; } @Override public Long hdel(String key, String... field) { Jedis jedis = jedisPool.getResource(); Long result = jedis.hdel(key, field); jedis.close(); return result; } @Override public Boolean hexists(String key, String field) { Jedis jedis = jedisPool.getResource(); Boolean result = jedis.hexists(key, field); jedis.close(); return result; } @Override public List<String> hvals(String key) { Jedis jedis = jedisPool.getResource(); List<String> result = jedis.hvals(key); jedis.close(); return result; } @Override public Long del(String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.del(key); jedis.close(); return result; } }
JedisClientCluster(集群版)JedisClientCluster可以直接set、get
package cn.tsu.e3mall.jedis; import java.util.List; import redis.clients.jedis.JedisCluster; public class JedisClientCluster implements JedisClient { private JedisCluster jedisCluster; public JedisCluster getJedisCluster() { return jedisCluster; } public void setJedisCluster(JedisCluster jedisCluster) { this.jedisCluster = jedisCluster; } @Override public String set(String key, String value) { return jedisCluster.set(key, value); } @Override public String get(String key) { return jedisCluster.get(key); } @Override public Boolean exists(String key) { return jedisCluster.exists(key); } @Override public Long expire(String key, int seconds) { return jedisCluster.expire(key, seconds); } @Override public Long ttl(String key) { return jedisCluster.ttl(key); } @Override public Long incr(String key) { return jedisCluster.incr(key); } @Override public Long hset(String key, String field, String value) { return jedisCluster.hset(key, field, value); } @Override public String hget(String key, String field) { return jedisCluster.hget(key, field); } @Override public Long hdel(String key, String... field) { return jedisCluster.hdel(key, field); } @Override public Boolean hexists(String key, String field) { return jedisCluster.hexists(key, field); } @Override public List<String> hvals(String key) { return jedisCluster.hvals(key); } @Override public Long del(String key) { return jedisCluster.del(key); } }
applicationContext-redis.xml关于redis的配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd"> <!-- 1、搭建单机版redis --> <bean id="jedisClientPool" class="cn.tsu.e3mall.jedis.JedisClientPool"> <property name="jedisPool" ref="jedisPool" /> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg name="host" value="192.168.25.110" /> <constructor-arg name="port" value="6379" /> </bean> <!--2、搭建集群版redis --> <!-- <bean id="jedisClientCluster" class="cn.tsu.e3mall.jedis.JedisClientCluster"> <property name="jedisCluster" ref="jedisCluster" /> </bean> <bean id="jedisCluster" class="redis.clients.jedis.JedisCluster"> <!--构造方法注入 --> <constructor-arg> <set> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="192.168.25.110" /> <constructor-arg name="port" value="7001" /> </bean> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="192.168.25.110" /> <constructor-arg name="port" value="7002" /> </bean> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="192.168.25.110" /> <constructor-arg name="port" value="7003" /> </bean> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="192.168.25.110" /> <constructor-arg name="port" value="7004" /> </bean> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="192.168.25.110" /> <constructor-arg name="port" value="7005" /> </bean> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="192.168.25.110" /> <constructor-arg name="port" value="7006" /> </bean> </set> </constructor-arg> </bean> --> </beans>
service层:(首页大广告的缓存(应该内容很少,故设置为永存,无TTL过期时间))
业务逻辑:
先从缓存中查询,若有返回数据
若缓存中没有,则去数据库查询,
然后再保存到缓存中。
添加缓存不能影响正常的逻辑,
因此都需要try{} catch()
// 首页回显广告 @Override public List<TbContent> findad1List(Long category_id) { try { //先从redis中调取 String jsonlist = jedisClient.hget(Commons.CONTENT_LIST, category_id+""); if (jsonlist !=null ) { List<TbContent> list = JsonUtils.jsonToList(jsonlist, TbContent.class); return list; } } catch (Exception e) { e.printStackTrace(); } TbContentExample example = new TbContentExample(); example.createCriteria().andCategoryIdEqualTo(category_id); List<TbContent> list = contentMapper.selectByExample(example); try { jedisClient.hset(Commons.CONTENT_LIST, category_id+"", JsonUtils.objectToJson(list)); } catch (Exception e) { e.printStackTrace(); } return list; }
controller层:
@Controller public class ContentController { @Autowired private ContentService contentService; @RequestMapping("/index") public String showIndex(Model model) { //回显大广告 List<TbContent> ad1list = contentService.findad1List(89l); model.addAttribute("ad1List", ad1list); return "index"; } }
来源:https://www.cnblogs.com/xiaofeng88/p/10317335.html