①. redis是一款高性能的开源NOSQL系列的非关系型数据库,Redis是用C语言开发的一个开源的高键值对(key value)数据库,官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s,且Redis通过提供多种键值数据类型来适应不同场景下的存储需求,目前Redis支持的键值数据类型如下:(字符串类型String、哈希类型hash、列表类型list、集合类型set、有序集合类型sortedset)
②. 缓存思想:从缓存中获取数据
有数据,直接返回
没有数据,从数据库查询,将数据放入缓存,返回数据
③. 使用场景
①. Redis6.0.9安装
②. Redis官网、Redis中文官方网址
③. linux下Redis的目录信息
2>.
数据结构介绍
1.
redis的数据结构
redis存储的是:key,value格式的数据,其中key都是字符串,value有5种不同的数据结构如下:
①. 字符串类型 string
②. 列表类型 list :linkedlist格式。支持重复元素
③. 集合类型 set :不允许重复元
④. 哈希类型 hash :map格式
⑤. 有序集合类型 sortedset:不允许重复元素,且元素有顺序
2.
字符串类型:String
①. 存储: set key value
②. 获取: get key
③. 删除:del key
3.
hash类型
①. 存储: hset key field value
②. 获取:hget key field: 获取指定的field对应的值
③. 获取:hgetall key:获取所有的field和value
④. 删除: hdel key field
4.
列表类型 list
5.
集合类型set
不允许重复元素
①. 存储:sadd key value
②. smembers key:获取set集合中所有元素
③. 删除:srem key value:删除set集合中的某个元素
6.
有序集合类型 sortedset
不允许重复元素,且元素有顺序.每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序
①. 存储:zadd key score value
②. 获取:zrange key start end [withscores]
③.删除:zrem key value
7.
通用命令
①. keys * : 查询所有的键
②. type key : 获取键对应的value的类型
③. del key:删除指定的key value
3>.
持久化(了解)
redis是一个内存数据库,当redis服务器重启,获取电脑重启,数据会丢失,我们可以将redis内存中的数据持久化保存到硬盘的文件中
1.
RDB(持久化机制默认)
默认方式,不需要进行配置,默认就使用这种机制;
在一定的间隔时间中,检测key的变化情况,然后持久化数据
2.
AOF
4>.
Java客户端 Jedis(了解)
1.Jedis快速入门
public class JedisDemo1 { public static void main(String[] args) { Jedis jedis=new Jedis("localhost",6379); jedis.set("username","xiaozhi"); System.out.println(jedis.get("username")); jedis.close(); } }
2.
Jedis操作String
字符串类型 string:set 、get
注意:
当我们使用jedis.setex(“activeCode”,20,“hehe”):这里的意思是,将键为activeCode值为hehe存入redis中,20s后自动删除该键值对
3.
哈希类型 hash : map格式
①. hset() hget() hgetAll()
②. 获取hash的所有map中的数据: Map<String, String> user = jedis.hgetAll("user");
4.
列表操作(list)
①. 列表类型 list : linkedlist格式。支持重复元素
②. lpush / rpush || lpop / rpop || lrange start end : 范围获取
5.
集合类型 set : 不允许重复元素
6.
有序集合类型 sortedset
①. 不允许重复元素,且元素有顺序
②. 方法:zadd()zrange()
5>.
jedis连接池: JedisPool
连接池是一种与无限数量的并发用户共享有限数量的数据库连接的技术。最大总连接数( maxTotal ) 包括活动连接和空闲连接,即正在使用的连接和当前未使用的连接(它是所有连接的总和)。最大空闲 连接( maxIdle )是准备使用的连接(但当前未使用)
#最大活动对象数 redis.pool.maxTotal=1000 #最大能够保持idle状态的对象数 redis.pool.maxIdle=100 #最小能够保持idel状态的对象数 redis.pool.minIdle=50 #当池内没有返回对象时,最大等待时间 redis.pool.maxWaitMillis=10000 #当调用borrow Object方法时,是否进行有效性检查 redis.pool.testOnBorrow=true #当调用return Object方法时,是否进行有效性检查 redis.pool.testOnReturn=true #“空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1. redis.pool.timeBetweenEvictionRunsMillis=30000 #向调用者输出“链接”对象时,是否检测它的空闲超时; redis.pool.testWhileIdle=true # 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3. redis.pool.numTestsPerEvictionRun=50 #redis服务器的IP redis.ip=xxxxxx #redis服务器的Port redis1.port=6379
host=127.0.0.1 port=6379 maxTotal=50 maxIdle=10
[掌握]
public class JedisPoolUtils { private static JedisPool jedisPool; static{ //读取配置文件 InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties"); //创建Properties对象 Properties pro = new Properties(); //关联文件 try { pro.load(is); } catch (IOException e) { e.printStackTrace(); } //获取数据,设置到JedisPoolConfig中 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal"))); config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle"))); //初始化JedisPool jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port"))); } /** * 获取连接方法 */ public static Jedis getJedis(){ return jedisPool.getResource(); } }
6>.
案例(掌握)
需求:
(1). 提供index.html页面,页面中有一个省份 下拉列表
(2). 当页面加载完成后 发送ajax请求,加载所有省份
后台代码:
(1).servlet
(2).service
(3)dao
前台代码:
7>.
Spring整合Redis
注意: 因为在SptringMvc中有<mvc:annotation/> 或 <dubbo:annotation package="com.itheima.controller" /> 所以在@Autowired private JedisPool jedisPool中, 不用使用<context:annotation-config/> @Autowired可以注入成功!
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--Jedis连接池的相关配置--> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="200"> <!-- <value>200</value>--> </property> <property name="maxIdle" value="50"> <!-- <value>50</value>--> </property> <property name="testOnBorrow" value="true"/> <property name="testOnReturn" value="true"/> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg name="poolConfig" ref="jedisPoolConfig" /> <constructor-arg name="host" value="127.0.0.1" /> <constructor-arg name="port" value="6379" type="int" /> <constructor-arg name="timeout" value="30000" type="int" /> </bean> </beans>
注意: 因为Spring中有<context:component-scan> 或 <dubbo:annotation package="com.itheima.service" /> 所以在@Autowired private JedisPool jedisPool中, 不用使用<context:annotation-config/> @Autowired可以注入成功!
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--Jedis连接池的相关配置--> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="200"> <!-- <value>200</value>--> </property> <property name="maxIdle" value="50"> <!-- <value>50</value>--> </property> <property name="testOnBorrow" value="true"/> <property name="testOnReturn" value="true"/> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg name="poolConfig" ref="jedisPoolConfig" /> <constructor-arg name="host" value="127.0.0.1" /> <constructor-arg name="port" value="6379" type="int" /> <constructor-arg name="timeout" value="30000" type="int" /> </bean> </beans>
8>.
RedisTemplate
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies>
server: port: 80 spring: redis: localhost: 127.0.0.1 port: 6379
@RunWith(SpringRunner.class) @SpringBootTest public class RedisTest { @Autowired private RedisTemplate redisTemplate; @Test public void fun1(){ //1.字符串 redisTemplate.boundValueOps("myString").set("xiaozhi"); String myString = (String) redisTemplate.boundValueOps("myString").get(); System.out.println("字符串String类型"+myString); System.out.println("----------"); //2.hash 散列 redisTemplate.boundHashOps("myHash").put("name","xiaoxing"); redisTemplate.boundHashOps("myHash").put("age",23); Set keys = redisTemplate.boundHashOps("myHash").keys(); List values = redisTemplate.boundHashOps("myHash").values(); System.out.println("keys:"+keys); System.out.println("values"+values); System.out.println("----------"); //3.列表类型list redisTemplate.boundListOps("myList").leftPush("a","b"); redisTemplate.boundListOps("myList").rightPush("c"); List myList = redisTemplate.boundListOps("myList").range(0, -1); System.out.println("有序集合类型myList"+myList); System.out.println("----------"); //4.集合类型 redisTemplate.boundSetOps("mySet").add("a"); Set mySet = redisTemplate.boundSetOps("mySet").members(); System.out.println("集合类型mySet = " + mySet); System.out.println("----------"); //5.有序集合类型 redisTemplate.boundZSetOps("mySort").add("b",70); redisTemplate.boundZSetOps("mySort").add("c",50); Set mySort = redisTemplate.boundZSetOps("mySort").range(0, -1); System.out.println("有序集合类型mySort = " + mySort); } }
9>.
SpringDataRedis
1.SpringDataRedis简介
SpringDataRedis 属于Spring Data 家族一员,用于对redis的操作进行封装的框架
Spring Data ----- Spring 的一个子项目。Spring 官方提供一套数据层综合解决方案,用 于简化数据库访问,支持NoSQL和关系数据库存储。包括Spring Data JPA 、Spring Data Redis 、SpringDataSolr 、SpringDataElasticsearch 、Spring DataMongodb 等 框架
2.
SpringDataRedis快速入门
<dependencies> <!--缓存--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>2.0.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.5.RELEASE</version> </dependency> </dependencies>
redis.host=127.0.0.1 redis.port=6379 redis.pass= redis.database=0 redis.maxIdle=300 redis.maxWait=3000
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:redis-config.properties" /> <!-- redis 相关配置 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxWaitMillis" value="${redis.maxWait}" /> </bean> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> </bean> </beans>
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(value = {"classpath:applicationContext-redis.xml"}) public class TestValue { @Autowired private RedisTemplate redisTemplate; @Test public void setValue(){ //向name属性中去存xiaozhi redisTemplate.boundValueOps("name").set("xiaozhi"); } @Test public void getValue(){ Object name = redisTemplate.boundValueOps("name").get(); System.out.println("name = " + name);//name=xiaozhi } @Test public void deleteValue(){ Boolean flag = redisTemplate.delete("name"); System.out.println("flag = " + flag); } }
3.
五种基本类型操作redis
1.redisTemplate.boundValueOps("name").set("xiaozhi"); 2.Object redisTemplate.boundValueOps("name").get(); 3.boolean delete(Object Key) [set username xiaozhi get username del username]
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(value = {"classpath:applicationContext-redis.xml"}) public class TestValue { @Autowired private RedisTemplate redisTemplate; @Test public void setValue(){ //向name属性中去存xiaozhi redisTemplate.boundValueOps("name").set("xiaozhi"); } @Test public void getValue(){ Object name = redisTemplate.boundValueOps("name").get(); System.out.println("name = " + name);//name=xiaozhi } @Test public void deleteValue(){ Boolean flag = redisTemplate.delete("name"); System.out.println("flag = " + flag); } }
1.boundSetOps("mySet").add("小智"); 2.Set boundSetOps("mySet").members(); 3.Long boundSetOps("mySet").remove("小智"); sadd myset a smembers myset srem myset a
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(value = {"classpath:applicationContext-redis.xml"}) public class TestSet { @Autowired private RedisTemplate redisTemplate; @Test public void setValue(){ redisTemplate.boundSetOps("mySet").add("小智"); redisTemplate.boundSetOps("mySet").add("小幸"); redisTemplate.boundSetOps("mySet").add("洋洋"); } @Test public void getValue(){ Set mySet = redisTemplate.boundSetOps("mySet").members(); System.out.println("mySet = " + mySet); } @Test public void deleteValue(){ Long remove = redisTemplate.boundSetOps("mySet").remove("小智"); System.out.println(remove); }
1.redisTemplate.boundListOps("myList").leftPush("a"); redisTemplate.boundListOps("myList").rightPush("b"); 2.boundListOps("myList").range(0, -1); 3.boundListOps("myList").remove(1, "a"); [range(开始索引,查询个数)] 存储: lpush myList a rpush myList b 获取: lrange myList 0 -1 删除: lpop myList rpop myList
@Test public void SetValue(){ redisTemplate.boundListOps("myList").leftPush("a"); redisTemplate.boundListOps("myList").leftPush("b"); redisTemplate.boundListOps("myList").rightPush("c"); //bac } @Test public void getValue(){ //获取myList中的数据 List myList = redisTemplate.boundListOps("myList").range(0, -1); System.out.println("myList = " + myList);//myList = [b, a, c] //删除myList中的数据 Long result= redisTemplate.boundListOps("myList").remove(1, "a"); System.out.println("result = " + result);//result = 1 //再次遍历,只有bc List myList2= redisTemplate.boundListOps("myList").range(0, -1); System.out.println("myList2 = " + myList2);//myList2 = [b, c] }
1.boundHashOps("myhash").put("name","xiaozhi"); 2.获取: 获取所有的key:Set boundHashOps("myhash").keys(); 获取所有的value:List boundHashOps("myhash").values(); 通过某个key得到value:Object boundHashOps("myhash").get("name"); 3.删除: boundHashOps("myhash").delete("name"); hset myhash name xiaozhi hget myhash name hdel myhash name
@Autowired private RedisTemplate redisTemplate; @Test public void setValue(){ redisTemplate.boundHashOps("myhash").put("name","xiaozhi"); redisTemplate.boundHashOps("myhash").put("age","13"); } @Test public void getValue(){ //1.得到所有的key Set myhash = redisTemplate.boundHashOps("myhash").keys(); System.out.println("所有的key是: "+myhash); //2.得到所有的value List values = redisTemplate.boundHashOps("myhash").values(); System.out.println("得到的values是: "+values); //3.通过某个key得到value Object name = redisTemplate.boundHashOps("myhash").get("name"); System.out.println("name = " + name); } @Test public void deleteValue(){ //删除name=xiaozhi Long result = redisTemplate.boundHashOps("myhash").delete("name"); System.out.println("result = " + result); }
1.存值: boundZSetOps("myZset").add("xiaozhi",10); 2.获取值 从小到大获取值:Set boundZSetOps("myZset").range(0, -1); 倒序:从大到小 boundZSetOps("myZset").reverseRange(0, 3); 获取每个元素的key value: boundZSetOps("myZset").reverseRangeWithScores(0, -1); typedTuple.getScore() typedTuple.getValue() 3.给xiaozhi增加 score 100:boundZSetOps("myZset").incrementScore("xiaozhi",100);
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(value={"classpath:applicationContext-redis.xml"}) public class TestZSet { @Autowired private RedisTemplate redisTemplate; @Test public void setValue(){ //向ZSet集合中添加数据 redisTemplate.boundZSetOps("myZset").add("xiaozhi",10); redisTemplate.boundZSetOps("myZset").add("xiaoxing",20); redisTemplate.boundZSetOps("myZset").add("yangyang",30); } @Test public void getValue(){ //从小到大获取值 Set myZset1= redisTemplate.boundZSetOps("myZset").range(0, -1); System.out.println("从小到大获取值"+myZset1); //倒序:从大到小 //Set myZset2 = redisTemplate.boundZSetOps("myZset").reverseRange(0, -1); Set myZset2 = redisTemplate.boundZSetOps("myZset").reverseRange(0, 3); System.out.println("从大到小获取值"+myZset2); //获取每个元素的key value Set<ZSetOperations.TypedTuple> myZset4 = redisTemplate.boundZSetOps("myZset").reverseRangeWithScores(0, -1); for(ZSetOperations.TypedTuple typedTuple:myZset4){ System.out.println("获取的key为:"+typedTuple.getScore()); System.out.println("获取的value为:"+typedTuple.getValue()); } System.out.println("-------"); //给xiaozhi增加 score 100 redisTemplate.boundZSetOps("myZset").incrementScore("xiaozhi",100); Set<ZSetOperations.TypedTuple> myZset5 = redisTemplate.boundZSetOps("myZset").reverseRangeWithScores(0, -1); for(ZSetOperations.TypedTuple typedTuple:myZset5){ System.out.println("获取的key为:"+typedTuple.getScore()); System.out.println("获取的value为:"+typedTuple.getValue()); } } /* 从小到大获取值[xiaoxing, yangyang, xiaozhi] 从大到小获取值[xiaozhi, yangyang, xiaoxing] 获取的key为:110.0 获取的value为:xiaozhi 获取的key为:30.0 获取的value为:yangyang 获取的key为:20.0 获取的value为:xiaoxing ------- 获取的key为:210.0 获取的value为:xiaozhi 获取的key为:30.0 获取的value为:yangyang 获取的key为:20.0 获取的value为:xiaoxing * */ }
Boolean expire(long timeout, TimeUnit unit)
;redisTemplate.boundValueOps("name").set("itcast"); redisTemplate.boundValueOps("name").expire(10,TimeUnit.SECONDS);
10>.
缓存穿透、缓存击穿、缓存雪崩
1.
缓存穿透
①. 问题的产生:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id 为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据 库压力过大。如下面这段代码就存在缓存穿透的问题
②. 如下代码会产生缓存穿透
三点解决方案:
(1).接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
(2).从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为 key-0。这样可以防止攻击用户反复用同一个id暴力攻击。代码举例:
(3).使用缓存预热
缓存预热就是将数据提前加入到缓存中,当数据发生变更,再将最新的数据更新到缓 存
2.
缓存击穿
①. 问题的产生:缓存击穿是指缓存中没有但数据库中有的数据。这时由于并发用户特别多,同时读 缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压 力
②. 以下代码可能会产生缓存击穿:
③. 解决方案:
解决方案:
(1).设置热点数据永远不过期
(2).缓存预热
3.
缓存雪崩
①. 问题的产生:缓存雪崩是指缓存数据大批量到过期时间,而查询数据量巨大,引起数据库压力过 大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同 数据都过期了,很多数据都查不到从而查数据库
②. 解决方案:
1.缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生 2.设置热点数据永远不过期。 3.使用缓存预热
11>.
缓存预热具体代码实现
按照如下三步进行: 1.将mysql数据库中的数据加载到缓存 2.从缓存中查询缓存数据[查询操作] 3.更新缓存[增删改操作]
1.
分类导航缓冲预热实现
[掌握]
首页分类导航的渲染: 拿到数据后,在模板页面中进行三次循环即可 [注意:这里前端要一个树状的结构,我们需要一个parentId的字段] 思路有两种: 1.通过parentId=0 查询得到一级菜单,遍历一级菜单,得到二级菜单,遍历二级菜单, 得到三级菜单,不推荐使用,因为和数据库需要频繁的交互,交互次数=1+一级菜单数量+二级菜单数量 2.首先把符合条件的记录(每一级菜单列表)[推荐使用]
public List<Map> findByParentId(List<Category>categories,Integer parentId){ List<Map>listMap=new ArrayList<Map>(); for(Category category:categories){ if(category.getParentId().equals(parentId)){ Map map=new HashMap(); map.put("name",category.getName()); map.put("menus",findByParentId(categories,category.getId())); listMap.add(map); } } return listMap; }
@Component public class Init implements InitializingBean { public Init(){ /* System.out.println("1111111");*/ } @Autowired private CategoryService categoryService; public void afterPropertiesSet() throws Exception { System.out.println("缓存预热"); //加载商品分类导航缓存 categoryService.saveCategoryTreeToRedis(); } }
public void saveCategoryTreeToRedis() { Example example=new Example(Category.class); Example.Criteria criteria = example.createCriteria(); criteria.andEqualTo("isShow","1");//显示 example.setOrderByClause("seq");//排序 List<Category> categories = categoryMapper.selectByExample(example); List<Map> categoryTree = findByParentId(categories, 0); //存入redis redisTemplate.boundValueOps(CacheKey.CATEGROY_TREE).set(categoryTree); }
//首页分类导航渲染 public List<Map> findCategoryTree() { /* Example example=new Example(Category.class); Example.Criteria criteria = example.createCriteria(); criteria.andEqualTo("isShow","1");//显示 example.setOrderByClause("seq");//排序 List<Category> categories = categoryMapper.selectByExample(example); return findByParentId(categories,0);*/ //从缓存中提取分类 System.out.println("redis category "); return (List<Map>)redisTemplate.boundValueOps(CacheKey.CATEGROY_TREE).get(); }
2.
广告轮播图缓存
@Component public class Init implements InitializingBean { @Autowired private AdService adService; public void afterPropertiesSet() throws Exception { adService.saveAllAdToRedis(); } }
//通过position在数据库中查询所有符合的条件并保存到redis public void saveAdToRedisByPosition(String position) { Example example=new Example(Ad.class); Example.Criteria criteria = example.createCriteria(); criteria.andEqualTo("position",position); criteria.andLessThanOrEqualTo("startTime",new Date()); criteria.andGreaterThanOrEqualTo("endTime",new Date()); criteria.andEqualTo("status","1"); List<Ad> adList = adMapper.selectByExample(example); //将数据库查询的所有符合条件的adList存储到Redis redisTemplate.boundHashOps(CacheKey.AD).put(position,adList); } private List<String> getPosition(){ List<String> list=new ArrayList<String>(); list.add("index_lb"); //如果还有别的广告在这里添加 return list; } //从mysql中查询所有的数据 public void saveAllAdToRedis() { for(String position:getPosition()){ saveAdToRedisByPosition(position); } }
//根据广告位置查询广告列表 public List<Ad> findByPosition(String position) { /* //创建查询条件 Example example=new Example(Ad.class); Example.Criteria criteria = example.createCriteria(); criteria.andEqualTo("position",position); criteria.andLessThanOrEqualTo("startTime",new Date()); criteria.andGreaterThanOrEqualTo("endTime",new Date()); criteria.andEqualTo("status","1"); return adMapper.selectByExample(example);*/ System.out.println("redis Ad"); return (List<Ad>) redisTemplate.boundHashOps(CacheKey.AD).get(position); }
/** * 修改 * @param ad */ public void update(Ad ad) { //A -1 - - B +1 //position A String position = adMapper.selectByPrimaryKey(ad.getId()).getPosition(); adMapper.updateByPrimaryKeySelective(ad); /*修改后将redis数据将进行同步*/ saveAdToRedisByPosition(position); if(!position.equals(ad.getPosition())){ saveAdToRedisByPosition(ad.getPosition()); } }
/** * 新增 * @param ad */ public void add(Ad ad) { adMapper.insert(ad); /*新增后将redis数据将进行同步*/ saveAdToRedisByPosition(ad.getPosition()); } /** * 删除 * @param id */ public void delete(Integer id) { String position = adMapper.selectByPrimaryKey(id).getPosition(); adMapper.deleteByPrimaryKey(id); /*删除后将redis数据将进行同步*/ saveAdToRedisByPosition(position); }