通常而言目前的數據庫分類有幾種,包括 SQL/NSQL,,關係數據庫,鍵值數據庫等等 等,分類的標準也不以,Redis本質上也是一種鍵值數據庫的,但它在保持鍵值數據庫簡單快捷特點的同時,又吸收了部分關係數據庫的優點。從而使它的位置處於關係數據庫和鍵值數 據庫之間。Redis不僅能保存Strings類型的數據,還能保存Lists類型(有序)和Sets類型(無序)的數據,而且還能完成排序(SORT) 等高級功能,在實現INCR,SETNX等功能的時候,保證了其操作的原子性,除此以外,還支持主從複製等功能。
現在很流行用redis做緩存,本項目也先簡單地將redis緩存整合到SSM項目之中,主要有以下幾步:
1.pom.xml中引入jar包
<!--redis-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.1.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
2.新建spring-redis.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.2.xsd">
<!-- 緩存的層級-->
<context:component-scan base-package="com.lw.common.utils" />
<context:property-placeholder location="classpath:redis.properties" />
<!-- redis 相關配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<!-- redis單節點數據庫連接配置 -->
<bean id="JedisConnectionFactory"
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.pass}" />
<property name="poolConfig" ref="poolConfig" />
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="JedisConnectionFactory" />
</bean>
</beans>
在redis.properties中設置了redis服務器的所需的參數:
redis.host=127.0.0.1
redis.port=6379
redis.pass=password
#控制一個pool最多有多少個狀態爲idle(空閒)的jedis實例
redis.maxIdle=100
redis.maxActive=300
# 表示當borrow(引入)一個jedis實例時,最大的等待時間,如果超過等待時間(毫秒),則直接拋出JedisConnectionException;
redis.maxWait=3000
# 在borrow一個jedis實例時,是否提前進行validate操作;如果爲true,則得到的jedis實例均是可用的
redis.testOnBorrow=true
配置完成後將配置文件引入到Spring配置文件中<!-- 引入同文件夾下的redis屬性配置文件 -->
<import resource="spring-redis.xml" />
package com.lw.common.cache;
import java.util.List;
import java.util.Set;
import javax.annotation.Resource;
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;
import org.springframework.stereotype.Component;
@Component
public class RedisCache {
public final static String CAHCENAME = "cache";// 緩存名
public final static int CAHCETIME = 60;// 默認緩存時間
@Resource
private RedisTemplate redisTemplate;
// private SimpleCacheManager cacheManager;
public boolean putCache(String key, T obj) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
boolean result = redisTemplate.execute(new RedisCallback() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.setNX(bkey, bvalue);
}
});
return result;
}
public void putCacheWithExpireTime(String key, T obj, final long expireTime) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
redisTemplate.execute(new RedisCallback() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
connection.setEx(bkey, expireTime, bvalue);
return true;
}
});
}
public boolean putListCache(String key, List objList) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
boolean result = redisTemplate.execute(new RedisCallback() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.setNX(bkey, bvalue);
}
});
return result;
}
public boolean putListCacheWithExpireTime(String key, List objList, final long expireTime) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
boolean result = redisTemplate.execute(new RedisCallback() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
connection.setEx(bkey, expireTime, bvalue);
return true;
}
});
return result;
}
public T getCache(final String key, Class targetClass) {
byte[] result = redisTemplate.execute(new RedisCallback() {
@Override
public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
return connection.get(key.getBytes());
}
});
if (result == null) {
return null;
}
return ProtoStuffSerializerUtil.deserialize(result, targetClass);
}
public List getListCache(final String key, Class targetClass) {
byte[] result = redisTemplate.execute(new RedisCallback() {
@Override
public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
return connection.get(key.getBytes());
}
});
if (result == null) {
return null;
}
return ProtoStuffSerializerUtil.deserializeList(result, targetClass);
}
/**
* 精確刪除key
*
* @param key
*/
public void deleteCache(String key) {
redisTemplate.delete(key);
}
/**
* 模糊刪除key
*
* @param pattern
*/
public void deleteCacheWithPattern(String pattern) {
Set keys = redisTemplate.keys(pattern);
redisTemplate.delete(keys);
}
/**
* 清空所有緩存
*/
public void clearCache() {
deleteCacheWithPattern(RedisCache.CAHCENAME+"|*");
}
}
package com.lw.common.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
/**
* 序列話工具
*/
public class ProtoStuffSerializerUtil {
/**
* 序列化對象
* @param obj
* @return
*/
public static byte[] serialize(T obj) {
if (obj == null) {
throw new RuntimeException("序列化對象(" + obj + ")!");
}
@SuppressWarnings("unchecked")
Schema schema = (Schema) RuntimeSchema.getSchema(obj.getClass());
LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
byte[] protostuff = null;
try {
protostuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
throw new RuntimeException("序列化(" + obj.getClass() + ")對象(" + obj + ")發生異常!", e);
} finally {
buffer.clear();
}
return protostuff;
}
/**
* 反序列化對象
* @param paramArrayOfByte
* @param targetClass
* @return
*/
public static T deserialize(byte[] paramArrayOfByte, Class targetClass) {
if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
throw new RuntimeException("反序列化對象發生異常,byte序列爲空!");
}
T instance = null;
try {
instance = targetClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("反序列化過程中依據類型創建對象失敗!", e);
}
Schema schema = RuntimeSchema.getSchema(targetClass);
ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
return instance;
}
/**
* 序列化列表
* @param objList
* @return
*/
public static byte[] serializeList(List objList) {
if (objList == null || objList.isEmpty()) {
throw new RuntimeException("序列化對象列表(" + objList + ")參數異常!");
}
@SuppressWarnings("unchecked")
Schema schema = (Schema) RuntimeSchema.getSchema(objList.get(0).getClass());
LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
byte[] protostuff = null;
ByteArrayOutputStream bos = null;
try {
bos = new ByteArrayOutputStream();
ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer);
protostuff = bos.toByteArray();
} catch (Exception e) {
throw new RuntimeException("序列化對象列表(" + objList + ")發生異常!", e);
} finally {
buffer.clear();
try {
if (bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return protostuff;
}
/**
* 反序列化列表
* @param paramArrayOfByte
* @param targetClass
* @return
*/
public static List deserializeList(byte[] paramArrayOfByte, Class targetClass) {
if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
throw new RuntimeException("反序列化對象發生異常,byte序列爲空!");
}
Schema schema = RuntimeSchema.getSchema(targetClass);
List result = null;
try {
result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(paramArrayOfByte), schema);
} catch (IOException e) {
throw new RuntimeException("反序列化對象列表發生異常!", e);
}
return result;
}
}
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.0.8</version>
</dependency>
至此Spring整合redis緩存的配置工作便準備完成,下面便可在service層使用
package com.lw.service;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.lw.common.utils.RedisCache;
import com.lw.dao.UserMapper;
import com.lw.entity.User;
@Service
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
@Resource
private UserMapper userMapper;
@Resource
private RedisCache redisCache;
public User getUserById(int userId) {
String cache_key = RedisCache.CAHCENAME+"|getUserById"+userId;
User user = redisCache.getCache(cache_key, User.class);
if(user != null){
log.info("get cache with key:"+cache_key);
}else {
user = userMapper.selectByPrimaryKey(userId);
redisCache.putCacheWithExpireTime(cache_key, user, RedisCache.CAHCETIME);
log.info("put cache with key:"+cache_key);
}
return user;
}
}