推荐一个程序员的论坛网站:http://ourcoders.com/home/
以下内容使用到的技术有:Redis缓存、SpringMVC、Maven。项目中使用了redis缓存,目的是在业务场景中,提高SQL的查询效率,做出性能优化。先看pom.xml的配置文件中,Jedis是Redis的Java客户端,Jedis基本实现了Redis的所有功能。在使用的时候,我们创建一个Jedis对象,通过操作Jedis来操作Redis,实现我们的业务场景需求。项目中使用了Maven来托管,先看Jedis在pom文件中的配置如下:
<!-- Redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.0</version>
</dependency> <dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.5.0.RELEASE</version>
</dependency>
pom.xml中redis的配置文件
我们的pom.xml配置文件*有两部分,上述配置会导入jedis-2.7.0.jar包和spring-data-redis.jar包。我们再看配置文件app-context-cache.xml,其中配置了ip地址,端口号,以及数据库的访问密码。这部分配置利用了maven编译时,会扫描相应的配置文件动态加载,如maven会根据:dev.properties、pre.properties、production.properties;开发、测试、生产生成相应的配置文件:详情如下:
<?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:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- redis -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="100" />
<property name="maxIdle" value="20" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="minEvictableIdleTimeMillis" value="30000" />
<property name="testOnBorrow" value="true" />
</bean>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="poolConfig" ref="jedisPoolConfig" />
<property name="hostName">
<value>${redis.address}</value>
</property>
<property name="port">
<value>${redis.port}</value>
</property>
<property name="password">
<value>${redis.password}</value>
</property>
<property name="timeout" value="15000"></property>
<property name="usePool" value="true"></property>
</bean>
<bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<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> <bean id="cacheService" class="xx.xx.xx.xx.CacheService" /> </beans>
app-context-cache.xml配置文件
其中<bean id="cacheService" class="xx.xx.xx.xx.CacheService" />指定了缓存类所在的package包中。再来看具体的CacheService的使用。
/**
* 缓存操作
*/
public class CacheService { protected Logger logger = LoggerFactory.getLogger(getClass()); @Autowired
private RedisTemplate<String, Object> redisTemplate; /*
* 缓存最大过期时间-一个月
*/
public static final int EXPIRE_TIME_MAX = 30 * 24 * 3600; /*
* 缓存过期时间-半天
*/
public static final int EXPIRE_TIME_HALFDAY = 12 * 3600; /*
* 缓存过期时间-整天
*/
public static final int EXPIRE_TIME_ONEDAY = 24 * 3600; /******************************
********* 缓存操作 ***********
******************************/ /**
* 设置缓存
*
* @param key
* @param value
*/
public void putCache(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
} catch (Exception e) {
logger.error("PUT cache exception [key=" + key + ", value=" + value + "].", e);
}
} /**
* 设置缓存,并设定缓存时长(秒)
*
* @param key
* @param value
* @param expire
*/
public void putCache(String key, Object value, int expire) {
try { redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
} catch (Exception e) {
logger.error("PUT cache exception [key=" + key + ", value=" + value + ", expire=" + expire + "].", e);
}
} /**
* 获取缓存数据
*
* @param key
* @return
*/
public Object getCache(String key) {
try { return redisTemplate.opsForValue().get(key);
} catch (Exception e) {
logger.error("GET cache exception [key=" + key + "].", e);
}
return null;
} /**
* 删除缓存
*
* @param key
*/
public void removeCache(String key) {
try { redisTemplate.delete(key); } catch (Exception e) {
logger.error("Remove cache exception [key=" + key + "].", e);
}
} /******************************
********* 队列操作 ***********
******************************/ /**
* 队列缓存设置
*
* @param key
* @param value
*/
public void putQueue(String key, Object value) {
try { redisTemplate.opsForList().leftPush(key, value); } catch (Exception e) {
logger.error("PUT Queue cache exception [key=" + key + ", value=" + value + "].", e);
}
} /**
* 获取队列缓存
*
* @param key
* @return
*/
public Object getQueue(String key) {
try { return redisTemplate.opsForList().rightPop(key); } catch (Exception e) {
logger.error("GET Queue cache exception [key=" + key + "].", e);
return null;
}
} /******************************
********* 栈操作 ***********
******************************/
public void putStack(String key, Object value) {
try {
redisTemplate.opsForList().leftPush(key, value);
} catch (Exception e) {
logger.error("PUT Stack cache exception [key=" + key + ", value=" + value + "].", e);
}
} public Object getStack(String key) {
try {
return redisTemplate.opsForList().leftPop(key); } catch (Exception e) {
logger.error("GET Stack cache exception [key=" + key + "].", e);
return null;
}
} public int length(String key) { try {
return redisTemplate.opsForList().size(key).intValue();
} catch (Exception e) {
logger.error("GET cache length exception [key=" + key + "].", e);
return 0;
}
} public void expire(String key, long timeout, TimeUnit unit) {
try {
redisTemplate.expire(key, timeout, unit);
} catch (Exception e) {
logger.error("SET expire time exception [key=" + key + "].", e);
}
} /******************************
********* hash操作 ***********
******************************/
/**
* hash put all
*
* @param key
* @param map
* @date 2015年10月12日
*/
public void hputs(String key, HashMap<? extends Object, ? extends Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
} catch (Exception e) {
logger.error("PUT All Hash exception [key=" + key + "].", e);
}
} /**
* hash put
*
* @param key
* @param hashKey
* @param value
* @date 2015年10月12日
*/
public void hput(String key, Object hashKey, Object value) {
try {
redisTemplate.opsForHash().put(key, hashKey, value);
} catch (Exception e) {
logger.error("PUT Hash length exception [key=" + key + "].", e);
}
} /**
* hash get
*
* @param key
* @param hashKey
* @return
* @date 2015年10月12日
*/
public Object hget(String key, Object hashKey) {
try {
return redisTemplate.opsForHash().get(key, hashKey);
} catch (Exception e) {
logger.error("GET Hash exception [key=" + key + "].", e);
return null;
}
} /**
* hash remove
*
* @param key
* @param hashKey
* @date 2015年10月12日
*/
public void hrem(String key, Object hashKey) {
try {
redisTemplate.opsForHash().delete(key, hashKey);
} catch (Exception e) {
logger.error("DELETE Hash exception [key=" + key + "].", e);
}
} /**
* hash size
*
* @param key
* @return
* @date 2015年10月12日
*/
public long hsize(String key) {
try {
return redisTemplate.opsForHash().size(key);
} catch (Exception e) {
logger.error("GET Hash size exception [key=" + key + "].", e);
return 0;
}
} /**
* hash keys
*
* @param key
* @return
* @date 2015年10月12日
*/
public Set<?> hkeys(String key) {
try {
return redisTemplate.opsForHash().keys(key);
} catch (Exception e) {
logger.error("GET Hash size exception [key=" + key + "].", e);
return null;
}
} /**
* 取出Map
*/
public Map<Object,Object> hMap(String key){
try {
return redisTemplate.opsForHash().entries(key);
} catch (Exception e) {
logger.error("GET Map size exception [key=" + key + "].", e);
return null;
}
} /************************************************************
**********************zset 操作*****************************
************************************************************/
/**
*往Zset插入数据
*/
public void zsetPut(String key,Object hashKey,Double score){
try{
redisTemplate.opsForZSet().add(key, hashKey, score);
}catch(Exception e){
logger.error("PUT Zset exception [key=" + key + "].", e);
}
} /**
* 查询Zset,按照开始结束score
*/
public Set<?> zsetGet(String key,Double arg0,Double arg1){
try{
return redisTemplate.opsForZSet().rangeByScore(key, arg0, arg1);
}catch(Exception e){
logger.error("GET Zset exception [key=" + key + "].", e);
return null;
}
} /**
* 模糊查询
*/
public Set<String> fuzzyQuery(String pattern){
try{
return redisTemplate.keys(pattern);
}catch(Exception e){
logger.error("GET fuzzyQuery exception [key=" + pattern + "].", e);
return null;
}
} public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
} public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
}
CacheService.java类文件
我们使用快捷键:ctrl+o迅速浏览一下CacheService.java类文件中的方法:
其中有如下的方法:用于设置缓存。
/**
* 设置缓存
*
* @param key
* @param value
*/
public void putCache(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
} catch (Exception e) {
logger.error("PUT cache exception [key=" + key + ", value=" + value + "].", e);
}
}
设置缓存
做好了上述配置,再来看看我们项目中是如何使用他们的。
public TradingArea findById(Integer id) {
if (id == null)
return null;
TradingArea ta = tradingAreaMapper.selectByPrimaryKey(id);
if (ta == null || ta.getIsActive() == (byte) 0) {
return null;
}
return ta;
} /**
* @Description: 缓存数据查询
*/
@Cache(expire = CacheService.EXPIRE_TIME_HALFDAY)
public TradingArea getTradingArea(Integer id){
return findById(id);
}
两个方法
根据主键ID查找对应的对象,我们写了两个方法,其中第一个方法,是针对该对象的增删改查,所以必须要用到实时数据,不能使用缓存。第二个方法,很显然,上方添加了缓存注解,通过设置缓存的有效时间,我们凡是做为关联表来查询的时候,都可以使用缓存来提示效率。那么问题的核心来了,我们上方添加了一个有效时间的注解,项目中是怎么实现来帮助我们取缓存的呢?先看缓存的定义文件
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {
boolean notCacheNull() default false;
int expire() default CacheService.EXPIRE_TIME_ONEDAY ;
boolean requireNew() default false;
}
当上述注解加在方法上的时候,会被一个拦截器拦截,拦截器拦截到之后,就会执行我们想要让缓存来做的:有就取出,没有就查SQL,同时拷贝一份在缓存中。下述是拦截器的配置文件,如下:
<bean id="businessMethodInterceptor" class="com.XX.XX.interceptor.BusinessMethodInterceptor">
<property name="needRoutingDatasource" value="false" />
</bean>
我们来看一下拦截器,拦截了缓存注解之后,有哪些操作,代码如下:
/**
* 缓存处理
*/
if (thisMethod.isAnnotationPresent(Cache.class)) {
Cache annotation = thisMethod.getAnnotation(Cache.class);
Class<?> returnType = thisMethod.getReturnType();
if (returnType != null && !"void".equals(returnType.getName())) {
Object cache = null;
try {
CacheKey key = new CacheKey(thisMethod.getDeclaringClass(), thisMethod, invocation.getArguments());
if(!annotation.requireNew()){
cache = cacheService.getCache(key.toString());
}
if (cache == null) {
cache = invocation.proceed();
try {
cacheService.putCache(key.toString(), cache, annotation.expire());
} catch (Exception e) {
logger.error("Cache Annotation process PUT CACHE exception.", e);
}
}
return cache;
} catch (Exception e) {
logger.error("Cache Annotation process exception.", e);
}
}
}
return invocation.proceed();