环境:项目采用springMvc+spring4.25+hibernate5.08+Mysql
目的:将Redis作为缓存数据库,具体Redis的优势网上都有,就不在赘述了。
1.所需jar包
除了spring以及与hibnenate 相关的依赖包外 spring-data-redis-1.7.2.RELEASE.jar jedis-2.9.0.jar
commons-pool2-2.5.0.jar redis配置线程池
2.配置文件
springMVC.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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 启用spring mvc 注解 -->
<!-- 扫描注解 -->
<context:component-scan base-package="com.fh.panghu.controller"/>
<mvc:annotation-driven />
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- 静态资源(js/image)的访问 ,可添加多个-->
<mvc:resources location="/views/images/" mapping="/views/images/**"/>
<mvc:resources location="/views/js/" mapping="/views/js/**"/>
<mvc:resources location="/views/css/" mapping="/views/css/**"/>
<!-- 定义跳转的文件的前后缀 ,视图模式配置 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 这里的配置自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/views/" />
<property name="suffix" value=".html" />
</bean>
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.Throwable">error</prop>
</props>
</property>
</bean>
<!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->
<bean name="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="utf-8" />
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760000" />
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>
</beans>
springCore2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-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/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/task
http://www.springframework.org/schema/task/spring-task-4.0.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">
<context:component-scan base-package="com.fh.panghu.service" />
<cache:annotation-driven />
<task:annotation-driven/>
<context:annotation-config/>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<context:component-scan base-package="com.fh.panghu.schedule"/>
<!-- 属性文件位置 -->
<!-- 公共配置文件信息 -->
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:public.properties</value>
</list>
</property>
</bean>
<!-- 读取数据库信息 -->
<bean id="annotationPropertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
<value>classpath:redis.properties</value>
</list>
</property>
</bean>
<!-- 配置线程池 -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="keepAliveSeconds" value="200" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="20" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
<!-- 配置数据源 c3p0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- 请求超时时间 -->
<property name="checkoutTimeout" value="30000" />
<!-- 每60秒检查所有连接池中的空闲连接。默认值: 0,不检查 -->
<property name="idleConnectionTestPeriod" value="30" />
<!-- 连接数据库连接池最大空闲时间 -->
<property name="maxIdleTime" value="30" />
<!-- 连接池初始化连接数 -->
<property name="initialPoolSize" value="5" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 -->
<property name="acquireIncrement" value="5" />
</bean>
<!-- 配置hibernate的SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 注入数据源 相关信息看源码 -->
<property name="dataSource" ref="dataSource" />
<!-- hibernate配置信息 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<!-- 开启二级缓存 ehcache -->
<prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">${hibernate.cache.provider_configuration_file_resource_path}
</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
</props>
</property>
<!-- 扫描hibernate注解配置的entity -->
<property name="packagesToScan" value="com.fh.panghu.entity" />
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Spring aop事务管理 -->
<aop:config proxy-target-class="true">
<aop:advisor pointcut="execution(* com.fh.panghu.service.*.*(..))" advice-ref="transactionAdvice" />
</aop:config>
<!-- 配置事务增强处理Bean,指定事务管理器 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<!-- 配置详细事务处理语义 -->
<tx:attributes>
<tx:method name="query*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="load*" read-only="true" />
<tx:method name="list*" read-only="true" />
<tx:method name="save*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
<tx:method name="update*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
<tx:method name="del*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
<tx:method name="create*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
<tx:method name="*" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean name="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- redis连接池配置-->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" >
<!--最大空闲数-->
<property name="maxIdle" value="${redis.maxIdle}" />
<!--连接池的最大数据库连接数 -->
<property name="maxTotal" value="${redis.maxTotal}" />
<!--最大建立连接等待时间-->
<property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
<!--逐出连接的最小空闲时间 默认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 >
<!--redis连接工厂 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="poolConfig" ref="jedisPoolConfig"></property>
<!--IP地址 -->
<property name="hostName" value="${redis.hostName}"></property>
<!--端口号 -->
<property name="port" value="${redis.port}"></property>
<!--如果Redis设置有密码 -->
<property name="password" value="${redis.password}" />
<!--客户端超时时间单位是毫秒 -->
<property name="timeout" value="${redis.timeout}"></property>
</bean>
<!--redis操作模版,使用该对象可以操作redis -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
<property name="connectionFactory" ref="jedisConnectionFactory" />
<!--如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!! -->
<property name="keySerializer" >
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer" >
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
<!--开启事务 -->
<property name="enableTransactionSupport" value="true"></property>
</bean >
<!-- 配置缓存 -->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg ref="redisTemplate" />
</bean>
</beans>
redis.properties
redis.hostName=127.0.0.1
redis.port=6379
redis.password=
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true
3.实现代码
RedisCacheUser.java 实体类 对应Mysql字段
@Entity
@Table(name="rediscacheuser")
public class RedisCacheUser {
//用户ID
private String redisuserid;
//名字
private String redisusername;
//密码
private String redispassword;
//ID
private String redisddid;
//用户电话
private String redismobile;
public RedisCacheUser(){
}
@Id
public String getUserid() {
return redisuserid;
}
public void setUserid(String userid) {
this. redisuserid = userid;
}
@Column(name="USERNAME",nullable=false,length=32)
public String getUsername() {
return redisusername;
}
public void setUsername(String username) {
this. redisusername = username;
}
@Column(name="PASSWORD",nullable=false,length=64)
public String getPassword() {
return redispassword;
}
public void setPassword(String password) {
this. redispassword = password;
}
@Column(name="DDID",nullable=false,length=128)
public String getDdid() {
return redisddid;
}
public void setDdid(String ddid) {
this.redisddid = ddid;
}
@Column(name="MOBILE",length=32)
public String getMobile() {
return redismobile;
}
public void setMobile(String mobile) {
this.redismobile = mobile;
}
@Override
public String toString() {
return "RedisCacheUser [redisuserid=" + redisuserid + ", redisusername=" + redisusername + ", redispassword="
+ redispassword + ", redisddid=" + redisddid + ", redismobile=" + redismobile + ", getUserid()="
+ getUserid() + ", getUsername()=" + getUsername() + ", getPassword()=" + getPassword() + ", getDdid()="
+ getDdid() + ", getMobile()=" + getMobile() + ", getClass()=" + getClass() + ", hashCode()="
+ hashCode() + ", toString()=" + super.toString() + "]";
}
}
RedisCacheTestService.java BaseTxService 里面封装了hibernate操作 可以通过hibernateTemplate操作Mysql
@Service
public class RedisCacheTestService extends BaseTxService {
@CachePut(key="#redisCacheUser.getUserid()",value="RedisCacheUser")
public String addRedisCacheTestUser(RedisCacheUser redisCacheUser) {
this.hibernateTemplate.save(redisCacheUser);
return JSONObject.fromObject(redisCacheUser).toString();
}
@CachePut(key="#redisCacheUser.getUserid()",value="RedisCacheUser")
public RedisCacheUser addRedisCacheTestUser1(RedisCacheUser redisCacheUser) {
this.hibernateTemplate.save(redisCacheUser);
return redisCacheUser;
}
/**
* 根据userId查询对象 先从缓存 没有则再数据库
* @param userId
* @return
*/
@Cacheable(key="#userId",value="RedisCacheUser")
@SuppressWarnings("unchecked")
public String getRedisCacheUserByuserId(String userId) {
String string = getRedisCacheUserByuserIdDB(userId);
return string;
}
public String getRedisCacheUserByuserIdDB(String userId) {
List <RedisCacheUser> redisCacheUsers = new ArrayList <RedisCacheUser>() ;
RedisCacheUser redisCacheUser = new RedisCacheUser() ;
redisCacheUsers = (List<RedisCacheUser>) this.hibernateTemplate.find("from RedisCacheUser where userid = '" + userId + "'");
if(redisCacheUsers.size()>0) {
redisCacheUser = redisCacheUsers.get(0);
return JSONObject.fromObject(redisCacheUser).toString();
}
return null;
}
/**
* 根据userName模糊查询多个对象 先从缓存 没有则再数据库
* @param userId
* @return
*/
/*@Cacheable(key="#username",value="RedisCacheUser")
@SuppressWarnings("unchecked")*/
public String getRedisCacheUsers(String username) {
String string = getRedisCacheUsersDB(username);
return string;
}
public String getRedisCacheUsersDB(String username) {
List <RedisCacheUser> redisCacheUsers = new ArrayList <RedisCacheUser>() ;
RedisCacheUser redisCacheUser = new RedisCacheUser() ;
redisCacheUsers = (List<RedisCacheUser>) this.hibernateTemplate.find("from RedisCacheUser where username like '%" + username + "%'");
if(redisCacheUsers.size()>0) {
System.out.println("redisCacheUsers:"+redisCacheUsers);
return JSONObject.fromObject(redisCacheUsers).toString();
}
return null;
}
/**
* 根据userName模糊查询多个对象 先从缓存 没有则再数据库
* @param username
* @return List
*/
/*@Cacheable(key="#username",value="RedisCacheUser")
@SuppressWarnings("unchecked")*/
public List<RedisCacheUser> getRedisCacheUsers1(String username) {
List <RedisCacheUser> redisCacheUsers = new ArrayList <RedisCacheUser>() ;
redisCacheUsers = (List<RedisCacheUser>) this.hibernateTemplate.find("from RedisCacheUser where username like '%" + username + "%'");
return redisCacheUsers;
}
/**
* 根据userId删除对象
* @param userId
* @return
*/
@CacheEvict(key="#redisCacheUser.getUserid()",value="RedisCacheUser")
public Boolean deleteRedisCacheUserByuserId(RedisCacheUser redisCacheUser) {
this.hibernateTemplate.delete(redisCacheUser);
// TODO Auto-generated method stub
return true;
}
/**
* 清空所有缓存 只是清除了Redis中的RedisCacheUser 但要删除数据库的需自己实现
* @return
*/
@CacheEvict(value="RedisCacheUser",allEntries=true)
public void deleteRedisCacheUsers() {
// TODO Auto-generated method stub
}
}
RedisCacheTest.java 使用Junit4测试
/*** 测试redis缓存和Mysql的增删查改DEMO JUnit测试
* @author Administrator
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:springCore2.xml", "classpath:springMVC.xml" })
public class RedisCacheTest {
@Autowired
private RedisCacheTestService redisCacheTestService;
/**
* 新增一条对象 缓存Redis为String的
*/
public void saveUser() {
RedisCacheUser user= new RedisCacheUser();
//构造数据
user.setUserid("2");
user.setDdid("1111");
user.setMobile("183213123");
user.setPassword("root");
user.setUsername("root");
redisCacheTestService.addRedisCacheTestUser(user);
}
/**
*根据ID获取String的
*/
public void getUserById() {
RedisCacheUser user= new RedisCacheUser();
String string = redisCacheTestService.getRedisCacheUserByuserId("13");
if(Objects.equals(string, null)) {
System.out.println("空空");
}else {
System.out.println(string);
}
}
/**
* 根据name 获取多个user string的
*/
public void getUsers() {
RedisCacheUser user= new RedisCacheUser();
String string = redisCacheTestService.getRedisCacheUsers("root");
if(Objects.equals(string, null)) {
System.out.println("空空");
}else {
System.out.println(string);
}
}
/**
* 新增一个缓存对象
*/
public void saveUser1() {
RedisCacheUser user= new RedisCacheUser();
//构造数据
user.setUserid("3");
user.setDdid("1111");
user.setMobile("183213123");
user.setPassword("root");
user.setUsername("root");
redisCacheTestService.addRedisCacheTestUser1(user);
}
/**
* 根据name返回对象List的
*/
public void getUsers1() {
RedisCacheUser user= new RedisCacheUser();
List<RedisCacheUser> redisCacheUsers= new ArrayList <RedisCacheUser>();
redisCacheUsers = redisCacheTestService.getRedisCacheUsers1("root");
if(redisCacheUsers.size()>0) {
System.out.println(JSONArray.fromObject(redisCacheUsers));
}else {
System.out.println("空空");
}
}
/**
* 删除Mysql数据库和Redis一个User对象
*/
public void deleteUser() {
//ArrayList<Object> redisCacheUsersObj = new ArrayList <Object>();
RedisCacheUser user= new RedisCacheUser();
//构造数据
user.setUserid("2");
user.setDdid("1111");
user.setMobile("183213123");
user.setPassword("root");
user.setUsername("root");
redisCacheTestService.deleteRedisCacheUserByuserId(user);
}
/**
* 清空Redis中所有的RedisCacheUser
*/
@Test
public void deleteUsers() {
redisCacheTestService.deleteRedisCacheUsers();
}
}
使用Redis视图工具查看