本文主要是介绍spring @Cacheable @CachePut... 使用redis缓存详细步骤,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
spring @Cacheable @CachePut... 使用redis缓存详细步骤
预期目标
查询:如果缓存中存在,直接从缓存中取,不查数据库。如果缓存中没有,从数据库查询并存入缓存,并设置超时时间。
修改:删除缓存中的内容(如果存在)。
删除:同步删除缓存中的内容。
实现步骤
pom,只列举关键部分,详细部分可以通过https://download.csdn.net/download/u013041642/10423952下载源码
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.0.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.1</version> </dependency>
web.xml
<web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mybatis.xml, classpath:spring-cache.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
spring-mvc.xml
<context:component-scan base-package="com.susq.work.*" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> </bean> </mvc:message-converters> </mvc:annotation-driven>
config.properties
## mysql database.url=jdbc:mysql://127.0.0.1/credit?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true database.username=root database.password= database.driverClass=com.mysql.jdbc.Driver ## redis redis.host=127.0.0.1 redis.port=6379 redis.password=foobared redis.timeout=60000 redis.database=0 redis.pool.maxActive=300 redis.pool.maxIdle=100 redis.pool.maxWait=2000
spring-mybatis.xml
<context:property-placeholder location="classpath:config.properties"/> <context:component-scan base-package="com.susq.work.*"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource_user"/> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> <bean id="dataSource_user" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${database.driverClass}"/> <property name="url" value="${database.url}"/> <property name="username" value="${database.username}"/> <property name="password" value="${database.password}"/> </bean> <bean id="userSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource_user"/> <property name="configLocation" value="classpath:sqlMapConfig.xml"/> <property name="mapperLocations" value="classpath*:com/susq/work/dao/mapper/UserMapper.xml"/> </bean> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="userSqlSessionFactory"/> <property name="basePackage" value="com.susq.work.dao"/> </bean>
spring-cache.xml
<context:property-placeholder location="classpath:config.properties" /> <cache:annotation-driven cache-manager="cacheManager"/> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.pool.maxActive}" /> <property name="maxIdle" value="${redis.pool.maxIdle}" /> <property name="maxWaitMillis" value="${redis.pool.maxWait}" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> </bean> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}"/> <property name="port" value="${redis.port}"/> <property name="password" value="${redis.password}" /> <property name="timeout" value="${redis.timeout}"/> <property name="database" value="${redis.database}"/> <property name="poolConfig" ref="jedisPoolConfig"/> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="connectionFactory" /> <property name="keySerializer" ref="keySerializer"/> <!-- key使用String序列化方式 --> <property name="hashKeySerializer" ref="keySerializer"/> <!-- value使用String序列化 --> <property name="valueSerializer" ref="jackson2JsonRedisSerializer"/> <!-- value使用json序列化 --> <!--<property name="hashValueSerializer" ref="jackson2JsonRedisSerializer"/>--> <property name="hashValueSerializer" ref="jdkSerializer"/> </bean> <bean id="keySerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/> <bean id="jackson2JsonRedisSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/> <bean id="jdkSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> <!-- spring自己的缓存管理器,这里定义了缓存位置名称 ,即注解中的value --> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <!-- 这里可以配置多个cache; 不同名称的缓存可以设置前缀用来区分缓存的类型,设置不同的超时时间或是redisTemplate,StringRedisTemplate --> <bean class="org.springframework.data.redis.cache.RedisCache"> <constructor-arg name="redisOperations" ref="redisTemplate"/> <constructor-arg name="name" value="common"/> <constructor-arg name="prefix" value=""/> <constructor-arg name="expiration" value="10" /> </bean> <bean class="org.springframework.data.redis.cache.RedisCache"> <constructor-arg name="redisOperations" ref="redisTemplate"/> <constructor-arg name="name" value="default"/> <constructor-arg name="prefix" value="DEF:"/> <!--这是通用的前缀--> <constructor-arg name="expiration" value="60"/> <!--这里的单位是秒--> </bean> </set> </property> </bean>
service实现类, 在对应的方法上加上注解
@Cacheable 调用方法时, 返回结果作为value放入缓存
@CachePut 调用方法时 方法入参作为value 放入缓存
@CacheEvict 调用方法是 从缓存中删除key 指定的数据
condition 方法调用前判断,满足时,存入缓存, condition 默认为“”
unless 方法调用后判断,满足时,不存 unless 默认为 “”
这里的spel 表达式中,#result 代表返回值, 比如第一个selectByPrimaryKey接口上的#result就代表返回的user实例。
package com.susq.work.service.impl; import com.susq.work.dao.UserMapper; import com.susq.work.model.User; import com.susq.work.service.UserService; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * @author susq * @since 2018-01-09-16:56 */ "userService") (public class UserServiceImpl implements UserService { private UserMapper userMapper; cacheNames = "common", key = "#id", unless = "#result != null") ( public User selectByPrimaryKey(String id) { return userMapper.selectByPrimaryKey(id); } value = "common", key = "#user.getId()") ( public User save(User user) { userMapper.saveUser(user); return user; } value = "common", key = "#user.getId()") ( public User update(User user) { userMapper.updateBySelective(user); return user; } value = "common", key = "#id") ( public void delete(String id) { userMapper.delete(id); } }
结果展示
写了个Controller 测一测,单元测试也可以
package com.susq.work.controller; import com.susq.work.model.User; import com.susq.work.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.HashMap; import java.util.Map; /** * @author susq * @since 2018-05-03-19:04 */ value = "/mybatis") (public class MybatisController { private UserService userService; value = "/get") ( public User getUser( String id) { User user = userService.selectByPrimaryKey(id); log.info("my log " + user); return user; } value = "/save") ( public Map<String, String> saveUser( User user) { userService.save(user); Map<String, String> result = new HashMap<>(); result.put("success", "00000000"); return result; } value = "/update") ( public void updateUser( User user) { userService.update(user); } value = "/delete") ( public Map<String, String> deleteUser( String id) { userService.delete(id); Map<String, String> result = new HashMap<>(); result.put("success", "00000000"); return result; } }
调两次get接口,可以看到日志如下, 第一次查询的时候,缓存中还没有,直接从数据库中查的,后面再请求就是从redis拿了。但是common缓存我配置的超时时间是10秒,10秒过后,再请求又会查一次数据库放入缓存了。
2018-05-18 21:52:35.405 DEBUG [http-nio-8090-exec-1]com.susq.work.dao.UserMapper.selectByPrimaryKey.debug:132 -==> Preparing: select id, name, address from user where id = ? 2018-05-18 21:52:35.468 DEBUG [http-nio-8090-exec-1]com.susq.work.dao.UserMapper.selectByPrimaryKey.debug:132 -==> Parameters: 1(String) 2018-05-18 21:52:35.493 DEBUG [http-nio-8090-exec-1]com.susq.work.dao.UserMapper.selectByPrimaryKey.debug:132 -<== Total: 1 2018-05-18 21:52:35.794 INFO [http-nio-8090-exec-1]com.susq.work.controller.MybatisController.getUser:30 -my log User(id=1, name=tingsuby, address=中国) 2018-05-18 21:52:38.797 INFO [http-nio-8090-exec-3]com.susq.work.controller.MybatisController.getUser:30 -my log User(id=1, name=tingsuby, address=中国)
也可以运行redis终端,请求一次get, 会看到我们的缓存已经加进去了,并且带着我们配置的前缀COMMON:
上面 配置的 valueSerializer 是GenericJackson2JsonRedisSerializer , 所以get 以后基本我们能看到我们存进去的原始信息,虽然汉字不能正常显示,起码比JdkSerializationRedisSerializer 辨识度好多了。
一些问题
@Cacheable注解不起作用
人们都说缓存的配置文件,要在spring的主配置文件中才生效,放在<context-param> 里面不起作用,我就直接在 spring-mvc.xml 中 import resouce 引入了spring-cache的配置文件,发现根本无卵用。除非在springMVC容器扫描的时候,扫描除Controller外所有的Bean 才起作用。但是SpringMVC 的容器我们只是放Controller 的Bean的,其余的Bean应该加载在Spring 主容器中,所以这样做并不好。 于是我试了一下放在web.xml 的 <context-param> 节点中时可以的。而且如果有多个文件,加载的顺序并不重要,例如
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mybatis.xml, classpath:spring-cache.xml</param-value> </context-param>
或者
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-cache.xml, classpath:spring-mybatis.xml</param-value> </context-param>
都是可以的。
这篇关于spring @Cacheable @CachePut... 使用redis缓存详细步骤的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!