spring+springmvc+mybatis+redis 实现两重数据缓存
2017-05-03 16:52 甘雨路 阅读(3740) 评论(0) 编辑 收藏 举报<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <!-- 配置springmvc核心 Servlet--> <servlet> <servlet-name>pringmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置文件加载的路径 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/config/springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>pringmvc</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping> <!-- END 配置springmvc核心 Servlet--> <!-- spring 路径的配置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/config/spring.xml</param-value> </context-param> <!--END spring 路径的配置 --> <!-- 配置spring监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--END 配置spring监听器 --> </web-app>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.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" > <!-- 包扫描 --> <context:component-scan base-package="sysone.zr.com" /> <!-- 开启Springmvc注解驱动 --> <mvc:annotation-driven /> <!-- SpringMVC视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 拦截器 --> <!-- <bean id="urlhandler" class="sysone.zr.com.interception.URLHandler"></bean> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/lf/online/**"/> <ref bean="urlhandler"/> </mvc:interceptor> </mvc:interceptors> --> </beans>
<?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:lang="http://www.springframework.org/schema/lang" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!-- 包扫描 --> <context:component-scan base-package="sysone.zr.com" /> <!-- 引入外部文件 --> <context:property-placeholder location="/WEB-INF/config/jdbc.properties,/WEB-INF/config/redis.properties"/> <!-- 开启动态代理 --> <aop:aspectj-autoproxy/> <!-- 事务属性配置 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- 事务传播属性 --> <tx:attributes> <!-- 所有已get、query、select开头的方法都是只读 --> <tx:method name="get*" read-only="true"/> <tx:method name="query*" read-only="true"/> <tx:method name="select*" read-only="true"/> <!-- 其它的所有方法支持事务设置的属性(异常回滚) --> <tx:method name="*" rollback-for="java.lang.Throwing" /> </tx:attributes> </tx:advice> <aop:config> <!-- 配置切点 --> <aop:pointcut id="fooServiceOperation" expression="execution(* sysone.zr.com.service.sysone.zr.com.service.impl.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/> </aop:config> <!-- 数据源配置 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" > <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 配置数据源管理器 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- mybatis配置 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="/WEB-INF/config/mybatis-config.xml"/> <property name="typeAliasesPackage" value="sysone.zr.com.mapper.model"/> <property name="mapperLocations"> <list> <value>classpath:sysone/zr/com/mapper/xml/*Mapper.xml</value> </list> </property> </bean> <!-- mybatis 扫描 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="sysone.zr.com.mapper.imapper"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> <!-- 配置redis 单机版 --> <!-- redis数据源 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大空闲数 --> <property name="maxIdle" value="${redis.maxIdle}" /> <!-- 最大空连接数 --> <property name="maxTotal" value="${redis.maxActive}" /> <!-- 最大等待时间 --> <property name="maxWaitMillis" value="${redis.maxWait}" /> <!-- 返回连接时,检测连接是否成功 --> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean> <!-- Spring-redis连接池管理工厂 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!-- IP地址 --> <property name="hostName" value="${redis.host}" /> <!-- 端口号 --> <property name="port" value="${redis.port}" /> <!-- 超时时间 --> <property name="timeout" value="${redis.timeout}" /> <property name="poolConfig" ref="poolConfig" /> </bean> <!-- redis 集群 --> <!-- <bean id="redisClient" class="redis.clients.jedis.JedisCluster"> <constructor-arg name="nodes"> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="192.168.10.105"></constructor-arg> <constructor-arg name="port" value="7002"></constructor-arg> </bean> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="192.168.10.77"></constructor-arg> <constructor-arg name="port" value="7002"></constructor-arg> </bean> </constructor-arg> </bean> --> <!-- redis模板类,提供了对缓存的增删改查 --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> <!-- StrRedisTemplate --> <bean id="strRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> </bean> <!-- 使用中间类解决RedisCache.jedisConnectionFactory的静态注入,从而使MyBatis实现第三方缓存 --> <bean id="redisCacheTransfer" class="sysone.zr.com.utils.RedisCacheTransfer"> <property name="jedisConnectionFactory" ref="jedisConnectionFactory"/> </bean> <!-- //End 单机版Redis集成 --> <!-- Redis缓存管理对象 --> <!-- <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"> <constructor-arg index="0" ref="redisTemplate" /> </bean> --> <!-- spring自己的换管理器,这里定义了两个缓存位置名称 ,既注解中的value --> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="sysone.zr.com.utils.SpringRedisCache"> <property name="redisTemplate" ref="redisTemplate" /> <property name="name" value="lf_cache"/> </bean> </set> </property> </bean> <!-- 开启Spring缓存 --> <cache:annotation-driven cache-manager="cacheManager"/> <!-- Spring容器实例 --> <!-- <bean class="sysone.zr.com.utils.SpringContext" /> --> </beans>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置mybatis的缓存,延迟加载等相关属性 --> <settings> <!-- 是否开启全局缓存 --> <setting name="cacheEnabled" value="true"/> <!-- 查询时,关闭关联对象即时加载以提高性能 --> <setting name="lazyLoadingEnabled" value="false"/> <!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 --> <setting name="multipleResultSetsEnabled" value="true"/> <!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 --> <setting name="aggressiveLazyLoading" value="true"/> </settings> </configuration>
redis.host=127.0.0.1
redis.port=6379
redis.maxIdle=2000
redis.maxActive=60000
redis.maxWait=1000
redis.testOnBorrow=true
redis.timeout=100000
defaultCacheExpireTime=60
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/cache_test
jdbc.username=root
jdbc.password=
package sysone.zr.com.controller; import java.util.List; import javax.annotation.Resource; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import sysone.zr.com.mapper.model.Person; import sysone.zr.com.service.PersonService; @Controller public class TestController { @Resource private PersonService personService; @RequestMapping("/person.htm") public void getPersonInfo(){ List<Person> persons = personService.getAllPerson(); if (persons!=null) { for (Person person : persons) { System.out.println("person:"+person); } } Person person = personService.getPersonById(100); System.out.println("person:"+person); } }
package sysone.zr.com.mapper.imapper; import java.util.List; import sysone.zr.com.mapper.model.Person; public interface PersonMapper { /** * 获取所有person的信息 * @return */ List<Person> getAllPerson(); Person getPersonById(int i); }
package sysone.zr.com.mapper.model;
import java.io.Serializable;
import org.springframework.cache.annotation.EnableCaching;
public class Person implements Serializable {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
super();
}
public Person(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="sysone.zr.com.mapper.imapper.PersonMapper"> <!-- 支持缓存配置 --> <cache type="sysone.zr.com.utils.RedisCache" /> <resultMap type="sysone.zr.com.mapper.model.Person" id="baseMap"> <id property="id" column="id" /> <result property="name" column="name"/> <result property="age" column="age"/> </resultMap> <select id="getAllPerson" resultMap="baseMap"> SELECT id,name,age FROM PERSON </select> <select id="getPersonById" parameterType="int" resultMap="baseMap"> SELECT id,name,age FROM PERSON WHERE id = #{id} </select> </mapper>
package sysone.zr.com.service.impl; import java.util.List; import javax.annotation.Resource; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.EnableCaching; import org.springframework.stereotype.Service; import sysone.zr.com.mapper.imapper.PersonMapper; import sysone.zr.com.mapper.model.Person; import sysone.zr.com.service.PersonService; @Service @EnableCaching public class PersonServerImpl implements PersonService { @Resource private PersonMapper mapper; @Cacheable(value="lf_cache",key="'getAllPerson'") public List<Person> getAllPerson() { System.out.println("===== 获取person信息 ====="); return mapper.getAllPerson(); } @Cacheable(value="lf_cache",key="'getPersonById'") public Person getPersonById(int i) { System.out.println("******getPersonById*******"); return mapper.getPersonById(i); } }
package sysone.zr.com.service; import java.util.List; import sysone.zr.com.mapper.model.Person; public interface PersonService { /** * 获取所有的person信息 * @return */ List<Person> getAllPerson(); Person getPersonById(int i); }
package sysone.zr.com.utils; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.ibatis.cache.Cache; import org.springframework.data.redis.connection.jedis.JedisConnection; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; public class RedisCache implements Cache { private static JedisConnectionFactory jedisConnectionFactory; private final String id; private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public RedisCache(final String id){ if (id == null) { throw new IllegalArgumentException("cache instances require an ID"); } this.id = id; } @Override public void clear() { JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); connection.flushDb(); connection.flushAll(); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } } @Override public String getId() { return this.id; } @Override public Object getObject(Object key) { Object result = null; JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = serializer.deserialize(connection.get(serializer.serialize(key))); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } return result; } @Override public ReadWriteLock getReadWriteLock() { return this.readWriteLock; } @Override public int getSize() { int result = 0; JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); result = Integer.valueOf(connection.dbSize().toString()); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } return result; } @Override public void putObject(Object key, Object value) { JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); System.out.println("**"+serializer.serialize(key)); connection.set(serializer.serialize(key), serializer.serialize(value)); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } } @Override public Object removeObject(Object key) { JedisConnection connection = null; Object result = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = connection.expireAt(serializer.serialize(key), 0); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } return result; } public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.jedisConnectionFactory = jedisConnectionFactory; } }
package sysone.zr.com.utils;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
public class RedisCacheTransfer {
public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
RedisCache.setJedisConnectionFactory(jedisConnectionFactory);
}
}
package sysone.zr.com.utils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import org.springframework.cache.Cache; import org.springframework.cache.support.SimpleValueWrapper; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; public class SpringRedisCache implements Cache{ private RedisTemplate<String, Object> redisTemplate; private String name; public RedisTemplate<String, Object> getRedisTemplate() { return redisTemplate; } public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) { this.redisTemplate = redisTemplate; } public void setName(String name) { this.name = name; } @Override public String getName() { // TODO Auto-generated method stub return this.name; } @Override public Object getNativeCache() { return this.redisTemplate; } @Override public ValueWrapper get(Object key) { System.out.println("get key"); final String keyf = key.toString(); Object object = null; object = redisTemplate.execute(new RedisCallback<Object>() { public Object doInRedis(RedisConnection connection) throws DataAccessException { byte[] key = keyf.getBytes(); byte[] value = connection.get(key); if (value == null) { return null; } return toObject(value); } }); return (object != null ? new SimpleValueWrapper(object) : null); } @Override public void put(Object key, Object value) { System.out.println("**************key"+key+"===value:"+value); System.out.println("put key"); final String keyf = key.toString(); final Object valuef = value; final long liveTime = 86400; redisTemplate.execute(new RedisCallback<Long>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { byte[] keyb = keyf.getBytes(); byte[] valueb = toByteArray(valuef); connection.set(keyb, valueb); if (liveTime > 0) { connection.expire(keyb, liveTime); } return 1L; } }); } private byte[] toByteArray(Object obj) { byte[] bytes = null; ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(obj); oos.flush(); bytes = bos.toByteArray(); oos.close(); bos.close(); }catch (IOException ex) { ex.printStackTrace(); } return bytes; } private Object toObject(byte[] bytes) { Object obj = null; try { ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bis); obj = ois.readObject(); ois.close(); bis.close(); } catch (IOException ex) { ex.printStackTrace(); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } return obj; } @Override public void evict(Object key) { // TODO Auto-generated method stub System.out.println("del key"); final String keyf = key.toString(); redisTemplate.execute(new RedisCallback<Long>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { return connection.del(keyf.getBytes()); } }); } @Override public void clear() { // TODO Auto-generated method stub System.out.println("clear key"); redisTemplate.execute(new RedisCallback<String>() { public String doInRedis(RedisConnection connection) throws DataAccessException { connection.flushDb(); return "ok"; } }); } @Override public <T> T get(Object key, Class<T> type) { // TODO Auto-generated method stub return null; } public ValueWrapper putIfAbsent(Object key, Object value) { // TODO Auto-generated method stub return null; } }