第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第七天】(redis缓存)

https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第五天】

第04项目:淘淘商城(SpringMVC+Spring+Mybatis) 的学习实践总结【第六天】

第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第七天】(redis缓存)

第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第八天】(solr服务器搭建、搜索功能实现)

第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第七天】(redis缓存)


 课程计划:

1、内容管理功能添加缓存。

a)       使用redis做缓存工具

b)       实现系统高可用,redis需要做主备。使用redis做分片集群。Redis集群的搭建。

c)       向业务逻辑中添加缓存。

2.1    访问taotao-portal服务406问题

1、查看是否Jackson包是否存在。

2、如果后缀是html是不能响应json数据的。需要修改后缀名。

2.2    Post乱码问题

produces=MediaType.TEXT_PLAIN_VALUE+";charset=utf-8"

 


 

使用redis做缓存安装的步骤详情见点击跳转

Redis 简介

Redis 是完全开源免费的,是一个高性能的key-value数据库。

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

 


 

2.7.3   Jedis客户端

使用前先引入依赖坐标

版本可以选用3.1.0

            <!-- Redis客户端 -->
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>${jedis.version}</version>
            </dependency>

 

RedisDesktopManager的使用注意事项:

第一步:在redis的配置文件(redis.conf)里面是否设置了requirepass  表示连接的密码,如果没有设置,则连接不上。或者关闭保护模式。

第二步:在redis的配置文件里面,在第69行左右是要已经把bind 127.0.0.1 给注释掉。如果没有,连接不上,。

 

package com.taotao.rest.jedis;

import java.util.HashSet;

import org.junit.Test;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;

public class JedisTest {
    @Test
    public void testJedisSingle() {
        //创建一个jedis的对象
        Jedis jedis = new Jedis("192.168.179.128",6379);
        jedis.auth("12345678");
        //调用jedis对象的方法,方法名称和redis的命令一致
        jedis.set("key1", "testJedisSingle");
        String string = jedis.get("key1");
        System.out.println(string);
        //关闭jedis
        jedis.close();        
    }
    
    /**
     * 使用连接池
     */
    @Test
    public void testJedisPool() {
        //创建jedis连接池
        JedisPool pool = new JedisPool("192.168.179.128", 6379);
        //从连接池中获得Jedis对象
        Jedis jedis = pool.getResource();
        jedis.auth("12345678");
        String string = jedis.get("key1");
        System.out.println(string);
        //关闭jedis对象
        jedis.close();
        pool.close();
    }
    
    //测试集群redis
    @Test
    public void testJedisCluster() throws Exception {
        HashSet<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("192.168.179.128", 7001));
        nodes.add(new HostAndPort("192.168.179.128", 7002));
        nodes.add(new HostAndPort("192.168.179.128", 7003));
        nodes.add(new HostAndPort("192.168.179.128", 7004));
        nodes.add(new HostAndPort("192.168.179.128", 7005));
        nodes.add(new HostAndPort("192.168.179.128", 7006));
        
        JedisCluster cluster = new JedisCluster(nodes);
        cluster.set("key2", "kang");
        
        String string = cluster.get("key2");
        System.out.println(string);
        
        cluster.close();
    }


}
View Code JedisTest

 

利用spring的IOC自动注入jedis的bean(参考资料:redis设置密码以及jedisPool设置密码

redis.properties

#redis单机版JedisPool配置信息
redis.hostName=192.168.179.128
redis.port=6379
redis.timeout=60
redis.password=12345678
View Code

application-jedis.xml

<?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: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.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
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 加载属性文件 -->
    <context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true" />
    <!-- 连接池配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大连接数 -->
        <property name="maxTotal" value="30" />
        <!-- 最大空闲连接数 -->
        <property name="maxIdle" value="10" />
        <!-- 每次释放连接的最大数目 -->
        <property name="numTestsPerEvictionRun" value="1024" />
        <!-- 释放连接的扫描间隔(毫秒) -->
        <property name="timeBetweenEvictionRunsMillis" value="30000" />
        <!-- 连接最小空闲时间 -->
        <property name="minEvictableIdleTimeMillis" value="1800000" />
        <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
        <property name="softMinEvictableIdleTimeMillis" value="10000" />
        <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
        <property name="maxWaitMillis" value="1500" />
        <!-- 在获取连接的时候检查有效性, 默认false -->
        <property name="testOnBorrow" value="true" />
        <!-- 在空闲时检查有效性, 默认false -->
        <property name="testWhileIdle" value="true" />
        <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
        <property name="blockWhenExhausted" value="false" />
    </bean>
    
    <!-- jedis客户端单机版配置 -->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="poolConfig"
            ref="jedisPoolConfig"></constructor-arg>
        <constructor-arg name="host" value="${redis.hostName}"></constructor-arg>
        <constructor-arg name="port" value="${redis.port}"></constructor-arg>
        <constructor-arg name="timeout" value="${redis.timeout}" type="int"/>
        <constructor-arg name="password" value="${redis.password}"></constructor-arg>    
    </bean>

    <bean id="jedisClientSingle"
        class="com.taotao.rest.dao.impl.JedisClientSingle"/>

    <!-- jedis集群版配置 -->
<!--     <bean id="redisClient" class="redis.clients.jedis.JedisCluster">
        <constructor-arg name="nodes">
            <set>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host"
                        value="192.168.179.128"></constructor-arg>
                    <constructor-arg name="port" value="7001"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host"
                        value="192.168.179.128"></constructor-arg>
                    <constructor-arg name="port" value="7002"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host"
                        value="192.168.179.128"></constructor-arg>
                    <constructor-arg name="port" value="7003"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host"
                        value="192.168.179.128"></constructor-arg>
                    <constructor-arg name="port" value="7004"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host"
                        value="192.168.179.128"></constructor-arg>
                    <constructor-arg name="port" value="7005"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host"
                        value="192.168.179.128"></constructor-arg>
                    <constructor-arg name="port" value="7006"></constructor-arg>
                </bean>
            </set>
        </constructor-arg>

        <constructor-arg name="poolConfig"
            ref="jedisPoolConfig"></constructor-arg>
    </bean>

    <bean id="jedisClientCluster"
        class="com.taotao.rest.dao.impl.JedisClientCluster" /> -->



</beans>
View Code

 

测试类的test方法

    @Test
    public void testSpringJedisCluster() throws IOException {
        //1.获取spring的IOC容器对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "classpath:spring/applicationContext-*.xml");
        //2.从IOC容器对象中取出bean的id为jedisCluster的那个
        JedisCluster jedisCluster = (JedisCluster) applicationContext.getBean("redisClient");

        jedisCluster.set("name", "kang");
        String value = jedisCluster.get("name");
        System.out.println(value); //console打印出kang就测试通过
        
        /* 最后要关闭jedis客户端 */
        jedisCluster.close();
    }

 


 /taotao-rest/src/main/java/com/taotao/rest/dao/JedisClient.java

package com.taotao.rest.dao;

public interface JedisClient {
    
    String get(String key);
    String set(String key,String value);
    String hget(String hkey,String key);
    long hset(String hkey,String key, String value);
    long incr(String key);
    long expire(String key,int second);
    long ttl(String key);
    //删除方法供后台更新内容管理调用
    long del(String key);
    long hdel(String hkey,String key );
}
package com.taotao.rest.dao.impl;

import org.springframework.beans.factory.annotation.Autowired;

import com.taotao.rest.dao.JedisClient;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class JedisClientSingle implements JedisClient {

    @Autowired
    private JedisPool jedisPool;

    @Override
    public String get(String key) {
        Jedis jedis = jedisPool.getResource();
        String string = jedis.get(key);
        jedis.close();
        return string;
    }

    @Override
    public String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        String string = jedis.set(key, value);
        jedis.close();
        return string;
    }

    @Override
    public String hget(String hkey, String key) {
        Jedis jedis = jedisPool.getResource();
        String string = jedis.hget(hkey, key);
        jedis.close();
        return string;
    }

    @Override
    public long hset(String hkey, String key, String value) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hset(hkey, key, value);
        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 expire(String key, int second) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.expire(key, second);
        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 del(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.del(key);
        jedis.close();
        return result;
    }
  

/taotao-rest/src/main/java/com/taotao/rest/dao/impl/JedisClientSingle.java

package com.taotao.rest.dao.impl;

import org.springframework.beans.factory.annotation.Autowired;

import com.taotao.rest.dao.JedisClient;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class JedisClientSingle implements JedisClient {

    @Autowired
    private JedisPool jedisPool;

    @Override
    public String get(String key) {
        Jedis jedis = jedisPool.getResource();
        String string = jedis.get(key);
        jedis.close();
        return string;
    }

    @Override
    public String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        String string = jedis.set(key, value);
        jedis.close();
        return string;
    }

    @Override
    public String hget(String hkey, String key) {
        Jedis jedis = jedisPool.getResource();
        String string = jedis.hget(hkey, key);
        jedis.close();
        return string;
    }

    @Override
    public long hset(String hkey, String key, String value) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hset(hkey, key, value);
        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 expire(String key, int second) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.expire(key, second);
        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 del(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.del(key);
        jedis.close();
        return result;
    }
    
    @Override
    public long hdel(String hkey,String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hdel(hkey,key);
        jedis.close();
        return result;
    }
    
}
View Code

/taotao-rest/src/main/java/com/taotao/rest/dao/impl/JedisClientCluster.java

package com.taotao.rest.dao.impl;

import org.springframework.beans.factory.annotation.Autowired;

import com.taotao.rest.dao.JedisClient;

import redis.clients.jedis.JedisCluster;

public class JedisClientCluster implements JedisClient {

    @Autowired
    private JedisCluster jedisCluster;
    
    @Override
    public String get(String key) {
        return jedisCluster.get(key);
    }

    @Override
    public String set(String key, String value) {
        return jedisCluster.set(key, value);
    }

    @Override
    public String hget(String hkey, String key) {
        return jedisCluster.hget(hkey, key);
    }

    @Override
    public long hset(String hkey, String key, String value) {
        return jedisCluster.hset(hkey, key, value);
    }

    @Override
    public long incr(String key) {
        return jedisCluster.incr(key);
    }

    @Override
    public long expire(String key, int second) {
        return jedisCluster.expire(key, second);
    }

    @Override
    public long ttl(String key) {
        return jedisCluster.ttl(key);
    }

    @Override
    public long del(String key) {
        return jedisCluster.del(key);
    }
    
    @Override
    public long hdel(String hkey,String key) {
        return jedisCluster.hdel(hkey,key);
    }

}
View Code
package com.taotao.rest.dao.impl;

import org.springframework.beans.factory.annotation.Autowired;

import com.taotao.rest.dao.JedisClient;

import redis.clients.jedis.JedisCluster;

public class JedisClientCluster implements JedisClient {

    @Autowired
    private JedisCluster jedisCluster;
    
    @Override
    public String get(String key) {
        return jedisCluster.get(key);
    }

    @Override
    public String set(String key, String value) {
        return jedisCluster.set(key, value);
    }

    @Override
    public String hget(String hkey, String key) {
        return jedisCluster.hget(hkey, key);
    }

    @Override
    public long hset(String hkey, String key, String value) {
        return jedisCluster.hset(hkey, key, value);
    }

    @Override
    public long incr(String key) {
        return jedisCluster.incr(key);
    }

    @Override
    public long expire(String key, int second) {
        return jedisCluster.expire(key, second);
    }

    @Override
    public long ttl(String key) {
        return jedisCluster.ttl(key);
    }

    @Override
    public long del(String key) {
        return jedisCluster.del(key)

5.3    把缓存添加到业务逻辑

注意:缓存的添加不能影响正常的业务逻辑。

/**
 * 内容管理
 * @author kangy
 *
 */
@Service
public class ContentServiceImpl implements ContentService {
    @Autowired
    private TbContentMapper contentMapper;
    //在XML配置文件中注入了bean
    @Autowired
    private JedisClient JedisClient;
    //从.properties文件读取常量
    @Value("${INDEX_CONTENT_REDIS_KEY}")
    private String INDEX_CONTENT_REDIS_KEY;

    @Override
    public List<TbContent> getContentList(long contentCid) {
        
        
        //b从缓存中取内容
        try {
            String result = JedisClient.hget(INDEX_CONTENT_REDIS_KEY, contentCid + "");
            if (!StringUtils.isBlank(result)) {
                //把字符串转换成list
                List<TbContent> resultList = JsonUtils.jsonToList(result, TbContent.class);
                return resultList;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        
        //a根据内容分类id查询内容列表
        TbContentExample example = new TbContentExample();
        TbContentExample.Criteria criteria = example.createCriteria();
        criteria.andCategoryIdEqualTo(contentCid);
        //a执行查询
        List<TbContent> list = contentMapper.selectByExampleWithBLOBs(example);

        
        //b向缓存中添加内容
        try {
            //把list转换成字符串
            String cacheString = JsonUtils.objectToJson(list);
            JedisClient.hset(INDEX_CONTENT_REDIS_KEY, contentCid + "", cacheString);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        //a返回结果
        return list;
    }

}
View Code
 打开win10下的图形化连接redis的工具软件查看是否成功地添加了商品信息内容的缓存到默认的database0

课后作业:商品类目展示添加缓存

 


6 缓存同步

当后台管理系统,修改内容之后需要通知redis把修改的内容对应的分类id的key删除。

6.1    添加缓存后的系统架构

6.2    解决方案

在taotao-rest工程中发布一个服务。当后台管理系统修改内容后,调用此服务,同步缓存。

6.3    Dao层

使用JedisClient接口对应的实现类。

6.4    Service层

接收内容分类id,调用dao删除redis中对应的hash中key为分类id的项。

参数:内容分类id

返回值:TaotaoResult

com.taotao.rest.service.impl.RedisServiceImpl

package com.taotao.rest.service.impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.ExceptionUtil;
import com.taotao.rest.dao.JedisClient;
import com.taotao.rest.service.RedisService;

@Service
public class RedisServiceImpl implements RedisService {
    
    @Autowired
    private JedisClient jedisClient;
    //从.properties文件读取常量
    @Value("${INDEX_CONTENT_REDIS_KEY}")
    private String INDEX_CONTENT_REDIS_KEY;
    
    
    @Override
    public TaotaoResult syncContent(long contentCid) {
        try {
            jedisClient.hdel(INDEX_CONTENT_REDIS_KEY, contentCid + "");
        } catch (Exception e) {
            e.printStackTrace();
            return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
        }

        return TaotaoResult.ok();
    }

}
View Code

6.5  Controller层

接收内容分类id,调用Service返回taotaoResult。

com.taotao.rest.controller.RedisController

@RestController
@RequestMapping("/cache/sync")
public class RedisController {
    @Autowired
    private RedisService redisService;

    @RequestMapping("/content/{contentCid}")
    public TaotaoResult contentCacheSync(@PathVariable Long contentCid) {
        TaotaoResult result = redisService.syncContent(contentCid);
        return result;
    }

}
View Code

http://localhost:8081/rest/cache/sync/content/89

 

6.6 同步缓存服务的调用

需要在后台管理系统中添加一个服务调用的逻辑。当修改内容信息后,需要调用此服务同步缓存。

 

com.taotao.service.impl.ContentServiceImpl

//内容管理
@Service
public class ContentServiceImpl implements ContentService {
    
    @Value("${REST_BASE_URL}")
    private String REST_BASE_URL;
    @Value("REST_CONTENT_SYNC_URL")
    private String REST_CONTENT_SYNC_URL;
    
    @Autowired
    private TbContentMapper contentMapper;
    
    @Override
    public TaotaoResult insertContent(TbContent content) {
        // 补全pojo内容
        content.setCreated(new Date());
        content.setUpdated(new Date());
        contentMapper.insert(content);

        // 添加缓存同步逻辑
        try {
            HttpClientUtil.doGet(REST_BASE_URL + REST_CONTENT_SYNC_URL + content.getCategoryId());
        } catch (Exception e) {
            // 通知管理员处理异常
            e.printStackTrace();
        }

        return TaotaoResult.ok();
    }

 

=======================================

参考资料:

redis 安装及集群部署

redis学习笔记(二)JedisCluster + redis 3.2.5集群

redis-4.0.14.gem集群创建用到的脚本 下载地址

Redis免费客户端 Another Redis DeskTop Manager 下载地址

RedisDesktopManager连接不上redis的解决方法

redis.clients. NOAUTH Authentication required 解决办法

end

posted @ 2019-10-16 21:54  Marlon康  阅读(624)  评论(0编辑  收藏  举报