spring的缓存(cache)-分布式缓存

tech2022-08-25  111

注:本文篇幅有点长,所以建议各位下载源码学习。(如需要请收藏!转载请声明来源,谢谢!)

代码下载:https://gitee.com/hong99/spring/issues/I1N1DF


目录

注:本文篇幅有点长,所以建议各位下载源码学习。(如需要请收藏!转载请声明来源,谢谢!)

代码下载:https://gitee.com/hong99/spring/issues/I1N1DF

背景

redis是什么?可以干嘛?

相关工具:

安装windows redis

源码实现

redis服务

spring data使用redis缓存,并且通过注解实现

测试多节点,请求redis缓存

redis手动式缓存

最后

代码实现:https://gitee.com/hong99/spring/issues/I1N1DF


背景

继上文《spring的缓存(cache)-本地》,本文实现集中式缓存(分布式);

redis是什么?可以干嘛?

Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。

参考文章:

基础教程:https://www.runoob.com/redis/redis-tutorial.html

官网:https://redis.io/

中文官网:https://www.redis.net.cn/

相关工具:

redis版本:Redis 3.2.100

redis客户端:RedisDesktopManager 0.9.3.817

spring 版本:4.x

安装windows redis

先查看电脑的是32或64位。此电脑->右键->属性

 

下载地址:https://github.com/MicrosoftArchive/redis/releases

安装参考这里:https://www.runoob.com/redis/redis-install.html

源码实现

redis服务

 

redis客户端

类图

spring data使用redis缓存,并且通过注解实现

    spring_mybatis_plus_redis_cache/pom.xml

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring</artifactId> <groupId>com.hong</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.hong</groupId> <artifactId>spring_mybatis_plus_redis_cache</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <logback.version>1.2.3</logback.version> <over-slf4j.version>1.7.25</over-slf4j.version> <spring.version>4.3.11.RELEASE</spring.version> <commons-dbcp.version>1.4</commons-dbcp.version> <slf4j.version>1.7.12</slf4j.version> <org.mybatis>3.1.0</org.mybatis> </properties> <dependencies> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>${org.mybatis}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-extension</artifactId> <version>${org.mybatis}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> <!--<dependency>--> <!--<groupId>org.springframework</groupId>--> <!--<artifactId>spring-jdbc</artifactId>--> <!--<version>${spring.version}</version>--> <!--</dependency>--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> </dependency> <!--引入连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency> <!--引入AOP--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <!--该包的主要作用是会去自动查找合适的日志记录框架进行记录--> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <!--引入日志--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.11.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.22</version> <optional>true</optional> </dependency> <!-- 实现slf4j接口并整合 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.2</version> </dependency> <!--引入hibernate--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.2.0.Final</version> </dependency> <!--引入orm--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!--引入redis--> <!-- Redis客户端 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <!-- redis Spring 基于注解配置 --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.8.1.RELEASE</version> </dependency> </dependencies> <!--静态资源导出问题--> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>UTF-8</encoding> <!--开启编译调试信息的开关--> <debug>true</debug> </configuration> </plugin> </plugins> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> </project>

redis.properties

#redis config #redids地址 redis.hostname=localhost #redis端口号 redis.port=6379 #超时时间 redis.timeout=2000 #默认db redis.default.db=0 #连接池的最大数据库连接数 redis.maxTotal=600 #最大空闲数 redis.maxIdle=300 #逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 redis.timeBetweenEvictionRunsMillis=30000 #逐出连接的最小空闲时间 默认1800000毫秒(30分钟) redis.minEvictableIdleTimeMillis=30000 #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个 redis.testOnBorrow=true #最大建立连接等待时间 redis.maxWait=-1 #在空闲时检查有效性, 默认false redis.testWhileIdle=true #每次释放连接的最大数目,默认3 redis.numTestsPerEvictionRun=1024

com.hong.spring.utils.RedisCacheConfig

package com.hong.spring.utils; import java.lang.reflect.Method; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; /** * 通过spring管理redis缓存配置 * * @author csh * */ @Configuration @EnableCaching public class RedisCacheConfig extends CachingConfigurerSupport { private volatile JedisConnectionFactory jedisConnectionFactory; private volatile RedisTemplate<String, String> redisTemplate; private volatile RedisCacheManager redisCacheManager; public RedisCacheConfig() { super(); } /** * 带参数的构造方法 初始化所有的成员变量 * * @param jedisConnectionFactory * @param redisTemplate * @param redisCacheManager */ public RedisCacheConfig(JedisConnectionFactory jedisConnectionFactory, RedisTemplate<String, String> redisTemplate, RedisCacheManager redisCacheManager) { this.jedisConnectionFactory = jedisConnectionFactory; this.redisTemplate = redisTemplate; this.redisCacheManager = redisCacheManager; } public JedisConnectionFactory getJedisConnecionFactory() { return jedisConnectionFactory; } public RedisTemplate<String, String> getRedisTemplate() { return redisTemplate; } public RedisCacheManager getRedisCacheManager() { return redisCacheManager; } @Bean public KeyGenerator customKeyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... objects) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : objects) { sb.append(obj.toString()); } return sb.toString(); } }; } }

其他的同上文一致。

com.hong.spring.service.UserServiceTest#findByIdTest

package com.hong.spring.service; import com.alibaba.fastjson.JSONObject; import lombok.extern.log4j.Log4j2; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @Auther: csh * @Date: 2020/8/24 11:17 * @Description:redis cache测试 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext-mybatis_plus_redis_cache.xml") @Log4j2 public class UserServiceTest { @Autowired private IUserService userService; /** * * 功能描述:查询 * * @param: * @return: * @auther: csh * @date: 2020/8/31 15:01 */ @Test public void findByIdTest() throws InterruptedException { log.info("第一次查:"+ JSONObject.toJSONString(userService.findById(1))); Thread.sleep(10000); log.info("第二次查:"+ JSONObject.toJSONString(userService.findById(1))); } /** * * 功能描述:删除缓存 * * @param: * @return: * @auther: csh * @date: 2020/8/31 15:01 */ @Test public void deleteCache(){ userService.deleteCache(1); } }

 结果:

15:05:51.235 [main] INFO com.hong.spring.service.impl.UserServiceImpl - 进入数据库查询 15:05:51.241 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 15:05:51.247 [main] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@571a9686] was not registered for synchronization because synchronization is not active 15:05:51.255 [main] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 15:05:51.256 [main] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@6aba5d30] will not be managed by Spring 15:05:51.259 [main] DEBUG com.hong.spring.dao.UserMapper.findById - ==> Preparing: SELECT * FROM user WHERE id = ? 15:05:51.279 [main] DEBUG com.hong.spring.dao.UserMapper.findById - ==> Parameters: 1(Integer) 15:05:51.293 [main] DEBUG com.hong.spring.dao.UserMapper.findById - <== Total: 1 15:05:51.295 [main] DEBUG com.alibaba.druid.pool.PreparedStatementPool - stmt enter cache 15:05:51.296 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@571a9686] 15:05:51.296 [main] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource 15:05:51.302 [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 15:05:51.311 [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 15:05:51.325 [main] INFO com.hong.spring.service.UserServiceTest - 第一次查:{"code":0,"data":{"age":100,"id":1,"username":"333"},"total":0} 15:06:01.326 [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 15:06:01.327 [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 15:06:01.327 [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 15:06:01.328 [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 15:06:01.331 [main] INFO com.hong.spring.service.UserServiceTest - 第二次查:{"code":0,"data":{"age":100,"id":1,"username":"333"},"total":0}

 

可以发现第一次查询有数据库记录,第二次查询直接是从redis中获取。

com.hong.spring.service.UserServiceTest#deleteCache

结果

发现已清空。

参考文章:

https://blog.csdn.net/u010996565/article/details/79953462

测试多节点,请求redis缓存

注:配置两个tomcat分别是8082和8081来请求同一个接口,看是否共享了。

第一次请求:http://localhost:8081/user/findById/1

发现请求了数据库,并且放到了redis中。

:53:10.351 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/findById/1] is: -1 17:53:10.411 [http-nio-8081-exec-5] DEBUG org.springframework.cache.annotation.AnnotationCacheOperationSource - Adding cacheable method 'findById' with attribute: [Builder[public com.hong.spring.utils.DataResponse com.hong.spring.service.impl.UserServiceImpl.findById(int)] caches=[findById] | key='#id' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'] 17:53:10.512 [http-nio-8081-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 17:53:10.626 [http-nio-8081-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 17:53:10.628 [http-nio-8081-exec-5] INFO com.hong.spring.service.impl.UserServiceImpl - 进入数据库查询 17:53:10.642 [http-nio-8081-exec-5] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 17:53:10.655 [http-nio-8081-exec-5] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4edba3a] was not registered for synchronization because synchronization is not active 17:53:10.674 [http-nio-8081-exec-5] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 17:53:10.675 [http-nio-8081-exec-5] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@3d88a0ae] will not be managed by Spring 17:53:10.682 [http-nio-8081-exec-5] DEBUG com.hong.spring.dao.UserMapper.findById - ==> Preparing: SELECT * FROM user WHERE id = ? 17:53:10.712 [http-nio-8081-exec-5] DEBUG com.hong.spring.dao.UserMapper.findById - ==> Parameters: 1(Integer) 17:53:10.739 [http-nio-8081-exec-5] DEBUG com.hong.spring.dao.UserMapper.findById - <== Total: 1 17:53:10.743 [http-nio-8081-exec-5] DEBUG com.alibaba.druid.pool.PreparedStatementPool - stmt enter cache 17:53:10.745 [http-nio-8081-exec-5] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4edba3a] 17:53:10.745 [http-nio-8081-exec-5] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource 17:53:10.756 [http-nio-8081-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 17:53:10.788 [http-nio-8081-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 17:53:10.918 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@2ddadd1c] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@2920b619] 17:53:10.918 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 17:53:10.918 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

 

 

再次请求

结果:发现没有再请求数据库,直接获取了redis数据。

17:54:41.406 [http-nio-8081-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'mybatis_plus_redis_cache' processing GET request for [/user/findById/1] 17:54:41.406 [http-nio-8081-exec-8] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /user/findById/1 17:54:41.407 [http-nio-8081-exec-8] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public com.hong.spring.utils.DataResponse<com.hong.spring.entity.User> com.hong.spring.controller.UserController.findById(java.lang.Integer)] 17:54:41.407 [http-nio-8081-exec-8] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userController' 17:54:41.407 [http-nio-8081-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/findById/1] is: -1 17:54:41.408 [http-nio-8081-exec-8] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 17:54:41.410 [http-nio-8081-exec-8] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 17:54:41.423 [http-nio-8081-exec-8] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 17:54:41.424 [http-nio-8081-exec-8] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 17:54:41.428 [http-nio-8081-exec-8] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@3a9ec1] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@2920b619] 17:54:41.429 [http-nio-8081-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 17:54:41.429 [http-nio-8081-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

 看看8082同一个地址。地址:http://localhost:8082/user/findById/1

结果:发现已实现了分布式缓存,不会再去查库了,而是直接返回redis结果。可以发现spring这个实现很nb

processing GET request for [/user/findById/1] 17:56:39.425 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /user/findById/1 17:56:39.426 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public com.hong.spring.utils.DataResponse<com.hong.spring.entity.User> com.hong.spring.controller.UserController.findById(java.lang.Integer)] 17:56:39.426 [http-nio-8082-exec-3] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userController' 17:56:39.426 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/findById/1] is: -1 17:56:39.542 [http-nio-8082-exec-3] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 17:56:39.628 [http-nio-8082-exec-3] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 17:56:39.635 [http-nio-8082-exec-3] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 17:56:39.636 [http-nio-8082-exec-3] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 17:56:39.756 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@6963905d] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@20ddf2cd] 17:56:39.756 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 17:56:39.756 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

再试试:http://localhost:8082/user/findById/2

结果:发现第一次请求了数据库并且缓存到了redis中,第二次后都是直接查询redis数据

第一次:

17:59:14.999 [http-nio-8082-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/findById/2] is: -1 17:59:14.999 [http-nio-8082-exec-9] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 17:59:15.001 [http-nio-8082-exec-9] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 17:59:15.013 [http-nio-8082-exec-9] INFO com.hong.spring.service.impl.UserServiceImpl - 进入数据库查询 17:59:15.029 [http-nio-8082-exec-9] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 17:59:15.040 [http-nio-8082-exec-9] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@60544f20] was not registered for synchronization because synchronization is not active 17:59:15.057 [http-nio-8082-exec-9] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 17:59:15.058 [http-nio-8082-exec-9] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@604f1509] will not be managed by Spring 17:59:15.063 [http-nio-8082-exec-9] DEBUG com.hong.spring.dao.UserMapper.findById - ==> Preparing: SELECT * FROM user WHERE id = ? 17:59:15.092 [http-nio-8082-exec-9] DEBUG com.hong.spring.dao.UserMapper.findById - ==> Parameters: 2(Integer) 17:59:15.111 [http-nio-8082-exec-9] DEBUG com.hong.spring.dao.UserMapper.findById - <== Total: 1 17:59:15.115 [http-nio-8082-exec-9] DEBUG com.alibaba.druid.pool.PreparedStatementPool - stmt enter cache 17:59:15.116 [http-nio-8082-exec-9] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@60544f20] 17:59:15.116 [http-nio-8082-exec-9] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource 17:59:15.119 [http-nio-8082-exec-9] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 17:59:15.143 [http-nio-8082-exec-9] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 17:59:15.144 [http-nio-8082-exec-9] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@582045f0] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@20ddf2cd] 17:59:15.144 [http-nio-8082-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 17:59:15.144 [http-nio-8082-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

第二次:

18:01:17.664 [http-nio-8082-exec-7] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'mybatis_plus_redis_cache' processing GET request for [/user/findById/2] 18:01:17.664 [http-nio-8082-exec-7] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /user/findById/2 18:01:17.665 [http-nio-8082-exec-7] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public com.hong.spring.utils.DataResponse<com.hong.spring.entity.User> com.hong.spring.controller.UserController.findById(java.lang.Integer)] 18:01:17.665 [http-nio-8082-exec-7] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userController' 18:01:17.666 [http-nio-8082-exec-7] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/findById/2] is: -1 18:01:17.666 [http-nio-8082-exec-7] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 18:01:17.668 [http-nio-8082-exec-7] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 18:01:17.669 [http-nio-8082-exec-7] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 18:01:17.670 [http-nio-8082-exec-7] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 18:01:17.671 [http-nio-8082-exec-7] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@9ce8e1f] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@20ddf2cd] 18:01:17.671 [http-nio-8082-exec-7] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 18:01:17.672 [http-nio-8082-exec-7] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

然后再查询另一个81的服务:

结果:发现不管怎么查询都使用了redis缓存,同上一样。

第一次查询

18:01:49.813 [http-nio-8081-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'mybatis_plus_redis_cache' processing GET request for [/user/findById/2] 18:01:49.813 [http-nio-8081-exec-9] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /user/findById/2 18:01:49.813 [http-nio-8081-exec-9] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public com.hong.spring.utils.DataResponse<com.hong.spring.entity.User> com.hong.spring.controller.UserController.findById(java.lang.Integer)] 18:01:49.814 [http-nio-8081-exec-9] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userController' 18:01:49.814 [http-nio-8081-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/findById/2] is: -1 18:01:49.814 [http-nio-8081-exec-9] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 18:01:49.816 [http-nio-8081-exec-9] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 18:01:49.817 [http-nio-8081-exec-9] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 18:01:49.818 [http-nio-8081-exec-9] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 18:01:49.820 [http-nio-8081-exec-9] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@df11bfe] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@2920b619] 18:01:49.821 [http-nio-8081-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 18:01:49.821 [http-nio-8081-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

第二次查询

18:02:23.680 [http-nio-8081-exec-1] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'mybatis_plus_redis_cache' processing GET request for [/user/findById/2] 18:02:23.680 [http-nio-8081-exec-1] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /user/findById/2 18:02:23.681 [http-nio-8081-exec-1] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public com.hong.spring.utils.DataResponse<com.hong.spring.entity.User> com.hong.spring.controller.UserController.findById(java.lang.Integer)] 18:02:23.681 [http-nio-8081-exec-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userController' 18:02:23.681 [http-nio-8081-exec-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/findById/2] is: -1 18:02:23.682 [http-nio-8081-exec-1] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 18:02:23.682 [http-nio-8081-exec-1] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 18:02:23.683 [http-nio-8081-exec-1] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 18:02:23.683 [http-nio-8081-exec-1] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 18:02:23.685 [http-nio-8081-exec-1] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@b234792] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@2920b619] 18:02:23.685 [http-nio-8081-exec-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 18:02:23.685 [http-nio-8081-exec-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

总结redis注解式

找了全网的资料发现极少涉及该通过redis注解式去实现,大部分都是手动的,当然注解式不管在单 机或者集群方式通过redis实现分布式事务非常便捷,但是涉及一些特殊操作比较麻烦。

redis手动式缓存

com.hong.spring.utils.RedisCacheManager

package com.hong.spring.utils; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.util.CollectionUtils; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; public class RedisCacheManager { private RedisTemplate<String, Object> redisTemplate; public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) { this.redisTemplate = redisTemplate; } /** * 指定缓存失效时间 * * @param key * 键 * @param time * 时间(秒) * @return */ public boolean expire(String key, long time) { try { if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据key 获取过期时间 * * @param key * 键 不能为null * @return 时间(秒) 返回0代表为永久有效 */ public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * 判断key是否存在 * * @param key * 键 * @return true 存在 false不存在 */ public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除缓存 * * @param key * 可以传一个值 或多个 */ @SuppressWarnings("unchecked") public void del(String... key) { if (key != null && key.length > 0) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete(CollectionUtils.arrayToList(key)); } } } // ============================String============================= /** * 普通缓存获取 * * @param key * 键 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通缓存放入 * * @param key * 键 * @param value * 值 * @return true成功 false失败 */ public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 普通缓存放入并设置时间 * * @param key * 键 * @param value * 值 * @param time * 时间(秒) time要大于0 如果time小于等于0 将设置无限期 * @return true成功 false 失败 */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 递增 * * @param key * 键 * @param by * 要增加几(大于0) * @return */ public long incr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * 递减 * * @param key * 键 * @param by * 要减少几(小于0) * @return */ public long decr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递减因子必须大于0"); } return redisTemplate.opsForValue().increment(key, -delta); } // ================================Map================================= /** * HashGet * * @param key * 键 不能为null * @param item * 项 不能为null * @return 值 */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 获取hashKey对应的所有键值 * * @param key * 键 * @return 对应的多个键值 */ public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key); } /** * HashSet * * @param key * 键 * @param map * 对应多个键值 * @return true 成功 false 失败 */ public boolean hmset(String key, Map<String, Object> map) { try { redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * * HashSet 并设置时间 * * @param key * 键 * @param map * 对应多个键值 * @param time * 时间(秒) * @return true成功 false失败 */ public boolean hmset(String key, Map<String, Object> map, long time) { try { redisTemplate.opsForHash().putAll(key, map); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * * @param key * 键 * @param item * 项 * @param value * 值 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value) { try { redisTemplate.opsForHash().put(key, item, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * * @param key * 键 * @param item * 项 * @param value * 值 * @param time * 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value, long time) { try { redisTemplate.opsForHash().put(key, item, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除hash表中的值 * * @param key * 键 不能为null * @param item * 项 可以使多个 不能为null */ public void hdel(String key, Object... item) { redisTemplate.opsForHash().delete(key, item); } /** * 判断hash表中是否有该项的值 * * @param key * 键 不能为null * @param item * 项 不能为null * @return true 存在 false不存在 */ public boolean hHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } /** * hash递增 如果不存在,就会创建一个 并把新增后的值返回 * * @param key * 键 * @param item * 项 * @param by * 要增加几(大于0) * @return */ public double hincr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, by); } /** * hash递减 * * @param key * 键 * @param item * 项 * @param by * 要减少记(小于0) * @return */ public double hdecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); } // ============================set============================= /** * 根据key获取Set中的所有值 * * @param key * 键 * @return */ public Set<Object> sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 根据value从一个set中查询,是否存在 * * @param key * 键 * @param value * 值 * @return true 存在 false不存在 */ public boolean sHasKey(String key, Object value) { try { return redisTemplate.opsForSet().isMember(key, value); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将数据放入set缓存 * * @param key * 键 * @param values * 值 可以是多个 * @return 成功个数 */ public long sSet(String key, Object... values) { try { return redisTemplate.opsForSet().add(key, values); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 将set数据放入缓存 * * @param key * 键 * @param time * 时间(秒) * @param values * 值 可以是多个 * @return 成功个数 */ public long sSetAndTime(String key, long time, Object... values) { try { Long count = redisTemplate.opsForSet().add(key, values); if (time > 0) expire(key, time); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 获取set缓存的长度 * * @param key * 键 * @return */ public long sGetSetSize(String key) { try { return redisTemplate.opsForSet().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 移除值为value的 * * @param key * 键 * @param values * 值 可以是多个 * @return 移除的个数 */ public long setRemove(String key, Object... values) { try { Long count = redisTemplate.opsForSet().remove(key, values); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } // ===============================list================================= /** * 获取list缓存的内容 * * @param key * 键 * @param start * 开始 * @param end * 结束 0 到 -1代表所有值 * @return */ public List<Object> lGet(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取list缓存的长度 * * @param key * 键 * @return */ public long lGetListSize(String key) { try { return redisTemplate.opsForList().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 通过索引 获取list中的值 * * @param key * 键 * @param index * 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 * @return */ public Object lGetIndex(String key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 将list放入缓存 * * @param key * 键 * @param value * 值 * @param time * 时间(秒) * @return */ public boolean lSet(String key, Object value) { try { redisTemplate.opsForList().rightPush(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key * 键 * @param value * 值 * @param time * 时间(秒) * @return */ public boolean lSet(String key, Object value, long time) { try { redisTemplate.opsForList().rightPush(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key * 键 * @param value * 值 * @param time * 时间(秒) * @return */ public boolean lSet(String key, List<Object> value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key * 键 * @param value * 值 * @param time * 时间(秒) * @return */ public boolean lSet(String key, List<Object> value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据索引修改list中的某条数据 * * @param key * 键 * @param index * 索引 * @param value * 值 * @return */ public boolean lUpdateIndex(String key, long index, Object value) { try { redisTemplate.opsForList().set(key, index, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 移除N个值为value * * @param key * 键 * @param count * 移除多少个 * @param value * 值 * @return 移除的个数 */ public long lRemove(String key, long count, Object value) { try { Long remove = redisTemplate.opsForList().remove(key, count, value); return remove; } catch (Exception e) { e.printStackTrace(); return 0; } } }

 applicationContext-mybatis_plus_redis_cache.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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:cache="http://www.springframework.org/schema/cache" 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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!-- 配置组件扫描 --> <context:component-scan base-package="com.hong.spring"></context:component-scan> <!--加载配置文件--> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <!-- 内部配置 --> <value>classpath:redis.properties</value> <value>classpath:jdbc.properties</value> </list> </property> <property name="fileEncoding" value="UTF-8"/> </bean> <!-- 开启注解 --> <context:annotation-config /> <!--开启注解事务--> <tx:annotation-driven transaction-manager="transactionManager" /> <!--放行静态资源--> <mvc:default-servlet-handler /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/pages/" /> <!-- 后缀 --> <property name="suffix" value=".html" /> <property name="contentType" value="text/html"/> </bean> <!--开启mvc注解事务--> <!-- 定义注解驱动 --> <mvc:annotation-driven> <mvc:message-converters> <!-- 设置支持中文 --> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> <value>text/html;charset=UTF-8</value> </list> </property> </bean> <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <!-- 基础配置 --> <property name="url" value="${jdbc.url}"></property> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="username" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <!-- 关键配置 --> <!-- 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 --> <property name="initialSize" value="3" /> <!-- 最小连接池数量 --> <property name="minIdle" value="2" /> <!-- 最大连接池数量 --> <property name="maxActive" value="15" /> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="10000" /> <!-- 性能配置 --> <!-- 打开PSCache,并且指定每个连接上PSCache的大小 --> <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> <!-- 其他配置 --> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000" /> <!-- 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。--> <property name="testWhileIdle" value="true" /> <!-- 这里建议配置为TRUE,防止取到的连接不可用 ,申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。--> <property name="testOnBorrow" value="true" /> <!-- 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 --> <property name="testOnReturn" value="false" /> </bean> <!--事务管理器--> <!-- sqlSessionFactory --> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <!-- 加载 MyBatis 的配置文件 --> <property name="configLocation" value="classpath:mybatis-plus.xml"/> <!-- 数据源 --> <property name="dataSource" ref="dataSource"/> <!-- 所有配置的mapper文件 --> <property name="mapperLocations" value="classpath*:com/hong/spring/mapper/*.xml" /> </bean> <!-- Mapper 扫描器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 扫描 包下的组件 --> <property name="basePackage" value="com.hong.spring.dao" /> <!-- 关联mapper扫描器 与 sqlsession管理器 --> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean> <!--事务配置--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- ******************** redis缓存 **********************--> <!-- 注解一定要配置,不然不起作用 --> <cache:annotation-driven cache-manager="cacheManager" /> <!-- 配置 JedisPoolConfig 实例 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!--最大空闲数--> <property name="maxIdle" value="${redis.maxIdle}"/> <!--连接池的最大数据库连接数 --> <property name="maxTotal" value="${redis.maxTotal}"/> <!--最大建立连接等待时间--> <property name="maxWaitMillis" value="${redis.maxWait}"/> <!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟)--> <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" /> <!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3--> <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" /> <!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1--> <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" /> <!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个--> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> <!--在空闲时检查有效性, 默认false --> <property name="testWhileIdle" value="${redis.testWhileIdle}" /> </bean> <!-- 配置JedisConnectionFactory --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!--IP地址 --> <property name="hostName" value="${redis.hostname}"></property> <!--端口号 --> <property name="port" value="${redis.port}"></property> <!--如果Redis设置有密码 --> <!--<property name="password" value="${redis.pa}" />--> <!--客户端超时时间单位是毫秒 --> <property name="timeout" value="${redis.timeout}"></property> <!--redis数据库序号,redis默认有16个库(从0-15),这里默认是0 --> <property name="database" value="${redis.default.db}"/> <property name="poolConfig" ref="poolConfig"/> </bean> <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" /> <!-- 配置RedisTemplate --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> <property name="keySerializer" ref="stringRedisSerializer" /> <property name="hashKeySerializer" ref="stringRedisSerializer" /> <property name="valueSerializer" ref="stringRedisSerializer"/> </bean> <!-- spring自己的缓存管理器,这里定义了缓存位置名称 ,即注解中的value --> <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"> <constructor-arg name="redisOperations" ref="redisTemplate"></constructor-arg> <property name="defaultExpiration" value="3000" /> </bean> <!-- 配置RedisCacheConfig --> <bean id="redisCacheConfig" class="com.hong.spring.utils.RedisCacheConfig"> <constructor-arg ref="jedisConnectionFactory" /> <constructor-arg ref="redisTemplate" /> <constructor-arg ref="cacheManager" /> </bean> <!--自定义redis工具类,在需要缓存的地方注入此类 --> <bean id="redisrCacheManager" class="com.hong.spring.utils.RedisCacheManager"> <property name="redisTemplate" ref="redisTemplate" /> </bean> <!-- ******************** redis缓存 **********************--> </beans>

com.hong.spring.service.IUserService#handlerById

/** * * 功能描述:手动查询id * * @param: * @return: * @auther: csh * @date: 2020/8/31 19:16 */ DataResponse<User> handlerById(Integer id);

com.hong.spring.service.impl.UserServiceImpl#handlerById

@Override public DataResponse <User> handlerById(Integer id) { if(null==id){ return DataResponse.BuildFailResponse("必传参数不能为空!"); } User user; String userStr = (String)redisCacheManager.get("user_" + id); if(null==userStr || StringUtils.isEmpty(userStr)){ user = userMapper.findById(id); if(null!=user){ redisCacheManager.set("user_"+id, JSONObject.toJSONString(user)); } }else{ user = JSONObject.parseObject(userStr, User.class); } return DataResponse.BuildSuccessResponse(user); }

com.hong.spring.controller.UserController#handlerById

@RequestMapping("handlerById/{id}") public DataResponse<User> handlerById(@PathVariable("id")Integer id){     if(null==id){         return DataResponse.BuildFailResponse("参数不能为空!");     }     try {         return userService.handlerById(id);     }catch (Exception e){         log.error("findById->查询失败{}",e);         return DataResponse.BuildFailResponse("查询出错请重试!");     } }

请求:http://localhost:8082/user/handlerById/2

结果:第一次查库,后面都是查redis

第一次

19:23:38.769 [http-nio-8082-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/handlerById/2] is: -1 19:23:38.839 [http-nio-8082-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 19:23:38.902 [http-nio-8082-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 19:23:38.917 [http-nio-8082-exec-5] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 19:23:38.932 [http-nio-8082-exec-5] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27f6fd76] was not registered for synchronization because synchronization is not active 19:23:38.949 [http-nio-8082-exec-5] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 19:23:38.951 [http-nio-8082-exec-5] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@374ddb17] will not be managed by Spring 19:23:38.956 [http-nio-8082-exec-5] DEBUG com.hong.spring.dao.UserMapper.findById - ==> Preparing: SELECT * FROM user WHERE id = ? 19:23:38.990 [http-nio-8082-exec-5] DEBUG com.hong.spring.dao.UserMapper.findById - ==> Parameters: 2(Integer) 19:23:39.012 [http-nio-8082-exec-5] DEBUG com.hong.spring.dao.UserMapper.findById - <== Total: 1 19:23:39.015 [http-nio-8082-exec-5] DEBUG com.alibaba.druid.pool.PreparedStatementPool - stmt enter cache 19:23:39.017 [http-nio-8082-exec-5] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27f6fd76] 19:23:39.017 [http-nio-8082-exec-5] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource 19:23:39.048 [http-nio-8082-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 19:23:39.048 [http-nio-8082-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection

第二次

19:23:45.642 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/handlerById/2] is: -1 19:23:45.642 [http-nio-8082-exec-3] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 19:23:45.643 [http-nio-8082-exec-3] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 19:23:45.666 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@71ad34fb] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@206ffcd3] 19:23:45.667 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 19:23:45.667 [http-nio-8082-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

请求:81服务。http://localhost:8081/user/handlerById/2

结果:每次都从缓存中取,给力。

19:29:55.970 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'mybatis_plus_redis_cache' processing GET request for [/user/handlerById/2] 19:29:55.970 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /user/handlerById/2 19:29:55.971 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public com.hong.spring.utils.DataResponse<com.hong.spring.entity.User> com.hong.spring.controller.UserController.handlerById(java.lang.Integer)] 19:29:55.971 [http-nio-8081-exec-5] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userController' 19:29:55.971 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/user/handlerById/2] is: -1 19:29:56.030 [http-nio-8081-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection 19:29:56.086 [http-nio-8081-exec-5] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection 19:29:56.215 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [com.hong.spring.utils.DataResponse@5412ad15] as "text/html" using [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@297a0692] 19:29:56.216 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mybatis_plus_redis_cache': assuming HandlerAdapter completed request handling 19:29:56.216 [http-nio-8081-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

最后

基本需要缓存方案的项目或者比较成熟的项目都会用到redis,而且用得特别多,当然也可以选择其他框架比如:Memcached,这里就不一一测试了。redis在高可用、高并发、高性能基本都杠杠的,当然也引发缓存穿透、缓存击穿、缓存雪崩、热点数据等问题。

建议下载源码学习:

代码实现:https://gitee.com/hong99/spring/issues/I1N1DF

如有疑问请私聊或请加QQ:718231657 

考虑文章长度所以:缓存穿透、缓存击穿、缓存雪崩、热点数据,放到下文。

最新回复(0)