由于之前对redis有了一个系统的研究,在公司的多个项目中使用redis当做数据缓存;所以趁着这些天晚上的时间,自己写了一个demo;这里仅供自己后期学习笔记参考,若有不对的地方,请轻拍砖!
redis 官网推荐给java 使用的客户端很多:Jedis、Redisson、JRedis、JDBC-Redis 等,当然首推是jedis;可以参考redis客户端官网查看。
接下来来讲下我的这个demo,我这个案例不是通过spring进行整合的redis,这个将会在之后的demo中讲到的。
(1).创建一个maven 功臣,在工程的pom 中引入jedis客户端;还有要依赖spring管理,所以也要引入spring相关jar包。
<span style="white-space:pre"> </span><dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis-version}</version>
</dependency>
<dependency>
(2).一般一个(系统)项目所用的redis服务器 多节点的集群服务器,所以会自己对(jedis)redis客户端进行封装,由于本例我自己写的是单节点,但是我还是按多节点的思路对客户端进行了封装。
redisClient类
/**
* redis 客户端封装
* @author leo
*
*/
public class RedisClient {
/**
* 日志记录
*/
private static final Log LOG = LogFactory.getLog(RedisClient.class);
/**
* redis 连接池
*/
private JedisPool pool;
public void setPool(JedisPool pool) {
this.pool = pool;
}
/**
* 获取jedis
* @return
*/
public Jedis getResource(){
Jedis jedis =null;
try {
jedis =pool.getResource();
} catch (Exception e) {
LOG.info("can't get the redis resource");
}
return jedis;
}
/**
* 关闭连接
* @param jedis
*/
public void disconnect(Jedis jedis){
jedis.disconnect();
}
/**
* 将jedis 返还连接池
* @param jedis
*/
public void returnResource(Jedis jedis){
if(null != jedis){
try {
pool.returnResource(jedis);
} catch (Exception e) {
LOG.info("can't return jedis to jedisPool");
}
}
}
/**
* 无法返还jedispool,释放jedis客户端对象,
* @param jedis
*/
public void brokenResource(Jedis jedis){
if (jedis!=null) {
try {
pool.returnBrokenResource(jedis);
} catch (Exception e) {
LOG.info("can't release jedis Object");
}
}
}
}
然后 通过spring的bean.xml 来管理 连接池,和连接池参数配置,以及redisClient 的依赖注入。
<!-- jedis 连接池配置参数: -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="100"></property>
<property name="maxIdle" value="25"></property>
<property name="maxWait" value="15000"></property>
<property name="testOnBorrow" value="false"></property>
<property name="testOnReturn" value="false"></property>
</bean>
<!-- jedis 连接池 连接本地redis服务 构造器注入-->
<bean id="pool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" ref="poolConfig"/>
<constructor-arg index="1" value="10.224.68.46"/>
<constructor-arg index="2" value="6379"/>
<constructor-arg index="3" value="2000"/>
</bean>
<!-- cleint-->
<bean id="redisClient" class="com.deppon.cache.redis.RedisClient">
<property name="pool" ref="pool"/>
</bean>
(3).创建好redisClient 之后,我要创造一个存储器,即一个对redis操作的工具容器。由于是公共容器,所以我创建接口是的容器接口就不该是封闭的,应该是开封的,保证存入数据库中对象类型的多态性。
存储器接口:
/**
*
* @author leo
*缓存存储接口
* @param <K> key
* @param <V> value
*/
public interface RedisCacheStorage<K, V> {
/**
* 在redis数据库中插入 key 和value
* @param key
* @param value
* @return
*/
boolean set(K key,V value);
/**
* 在redis数据库中插入 key 和value 并且设置过期时间
* @param key
* @param value
* @param exp 过期时间 s
* @return
*/
boolean set(K key, V value, int exp);
/**
* 根据key 去redis 中获取value
* @param key
* @return
*/
V get(K key);
/**
* 删除redis库中的数据
* @param key
* @return
*/
boolean remove(K key);
/**
* 设置哈希类型数据到redis 数据库
* @param cacheKey 可以看做一张表
* @param key 表字段
* @param value
* @return
*/
boolean hset(String cacheKey,K key,V value);
/**
* 获取哈希表数据类型的值
* @param cacheKey
* @param key
* @return
*/
V hget(String cacheKey,K key);
/**
* 获取哈希类型的数据
* @param cacheKey
* @return
*/
Map<K,V> hget(String cacheKey);
以及存储实现类:
/**
* redis 缓存存储器实现
* @author leo
*
* @param <V>
*/
public class RedisCacheStorageImpl<V> implements RedisCacheStorage<String, V> {
/**
* 日志记录
*/
public static final Log LOG = LogFactory.getLog(RedisCacheStorageImpl.class);
/**
* redis 客户端
*/
private RedisClient redisClient;
/**
* 默认过时时间
*/
private static final int EXPRIE_TIME =3600*24;
public void setRedisClient(RedisClient redisClient) {
this.redisClient = redisClient;
}
/**
* 在redis数据库中插入 key 和value
* @param key
* @param value
* @return
*/
@Override
public boolean set(String key, V value) {
//设置默认过时时间
return set(key, value, EXPRIE_TIME);
}
/**
* 在redis数据库中插入 key 和value 并且设置过期时间
* @param key
* @param value
* @param exp 过期时间 s
* @return
*/
@SuppressWarnings("finally")
@Override
public boolean set(String key, V value, int exp) {
Jedis jedis =null;
//将key 和value 转换成 json 对象
String jKey =CacheUtils.toJsonString(key);
String jValue =CacheUtils.toJsonString(value);
//操作是否成功
boolean isSucess =true;
if(StringUtils.isNotEmpty(jKey)){
LOG.info("key is empty");
return false;
}
try {
//获取客户端对象
jedis =redisClient.getResource();
//执行插入
jedis.setex(jKey, exp, jValue);
} catch (JedisException e) {
LOG.info("client can't connect server");
isSucess =false;
if(null !=jedis){
//释放jedis对象
redisClient.brokenResource(jedis);
}
return false;
}finally{
if(isSucess){
//返还连接池
redisClient.returnResource(jedis);
}
return true;
}
}
/**
* 根据key 去redis 中获取value
* @param key
* @return
*/
@SuppressWarnings("unchecked")
@Override
public V get(String key) {
Jedis jedis =null;
//将key 和value 转换成 json 对象
String jKey =CacheUtils.toJsonString(key);
V jValue =null;
//key 不能为空
if(StringUtils.isEmpty(jKey)){
LOG.info("key is empty");
return null;
}
try {
//获取客户端对象
jedis =redisClient.getResource();
//执行查询
String value = jedis.get(jKey);
//判断值是否非空
if(StringUtils.isEmpty(value)){
return null;
}else{
jValue= (V) CacheUtils.jsonParseObject(value);
}
//返还连接池
redisClient.returnResource(jedis);
} catch (JedisException e) {
LOG.info("client can't connect server");
if(null !=jedis){
//释放jedis 对象
redisClient.brokenResource(jedis);
}
}
return jValue;
}
/**
* 删除redis库中的数据
* @param key
* @return
*/
@SuppressWarnings("finally")
@Override
public boolean remove(String key) {
Jedis jedis =null;
//将key 和value 转换成 json 对象
String jKey =CacheUtils.toJsonString(key);
//操作是否成功
boolean isSucess =true;
if(StringUtils.isEmpty(jKey)){
LOG.info("key is empty");
return false;
}
try {
jedis =redisClient.getResource();
//执行删除
jedis.del(jKey);
} catch (JedisException e) {
LOG.info("client can't connect server");
isSucess =false;
if(null !=jedis){
//释放jedis 对象
redisClient.brokenResource(jedis);
}
return false;
}finally{
if (isSucess) {
//返还连接池
redisClient.returnResource(jedis);
}
return true;
}
}
/**
* 设置哈希类型数据到redis 数据库
* @param cacheKey 可以看做一张表
* @param key 表字段
* @param value
* @return
*/
@SuppressWarnings("finally")
@Override
public boolean hset(String cacheKey, String key, V value) {
Jedis jedis =null;
//将key 和value 转换成 json 对象
String jKey =CacheUtils.toJsonString(key);
String jCacheKey =CacheUtils.toJsonString(cacheKey);
String jValue =CacheUtils.toJsonString(value);
//操作是否成功
boolean isSucess =true;
if(StringUtils.isEmpty(jCacheKey)){
LOG.info("cacheKey is empty");
return false;
}
try {
jedis =redisClient.getResource();
//执行插入哈希
jedis.hset(jCacheKey, jKey, jValue);
} catch (JedisException e) {
LOG.info("client can't connect server");
isSucess =false;
if(null !=jedis){
//释放jedis 对象
redisClient.brokenResource(jedis);
}
return false;
}finally{
if (isSucess) {
//返还连接池
redisClient.returnResource(jedis);
}
return true;
}
}
/**
* 获取哈希表数据类型的值
* @param cacheKey
* @param key
* @return
*/
@SuppressWarnings("unchecked")
@Override
public V hget(String cacheKey, String key) {
Jedis jedis =null;
//将key 和value 转换成 json 对象
String jKey =CacheUtils.toJsonString(key);
String jCacheKey =CacheUtils.toJsonString(cacheKey);
V jValue =null;
if(StringUtils.isEmpty(jCacheKey)){
LOG.info("cacheKey is empty");
return null;
}
try {
//获取客户端对象
jedis =redisClient.getResource();
//执行查询
String value = jedis.hget(jCacheKey, jKey);
//判断值是否非空
if(StringUtils.isEmpty(value)){
return null;
}else{
jValue= (V) CacheUtils.jsonParseObject(value);
}
//返还连接池
redisClient.returnResource(jedis);
} catch (JedisException e) {
LOG.info("client can't connect server");
if(null !=jedis){
//释放jedis 对象
redisClient.brokenResource(jedis);
}
}
return jValue;
}
/**
* 获取哈希类型的数据
* @param cacheKey
* @return
*/
@Override
public Map<String, V> hget(String cacheKey) {
String jCacheKey =CacheUtils.toJsonString(cacheKey);
//非空校验
if(StringUtils.isEmpty(jCacheKey)){
LOG.info("cacheKey is empty!");
return null;
}
Jedis jedis =null;
Map<String,V> result =null;
try {
jedis =redisClient.getResource();
//获取列表集合
Map<String,String> map = jedis.hgetAll(jCacheKey);
if(null !=map){
for(Map.Entry<String, String> entry : map.entrySet()){
if(result ==null){
result =new HashMap<String,V>();
}
result.put((String) CacheUtils.jsonParseObject(entry.getKey()), (V)CacheUtils.jsonParseObject(entry.getValue()));
}
}
} catch (JedisException e) {
LOG.info("client can't connect server");
if(null !=jedis){
//释放jedis 对象
redisClient.brokenResource(jedis);
}
}
return result;
}
}
(4),接下来要把写个具体的业务UserService,来测试redis的存储器在具体业务中的使用,即实现(非关系型数据库的持久化操作)。本例中的例子是经常项目中对user的操作
创建UserEntity实体类:
/**
* 用户实体类
* @author leo
*
*/
public class UserEntity {
//用户id
private String userId;
//用户账号
private String EmpCode;
//用户名称
private String EmpName;
//用户角色
private String role;
//职位
private String title;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getEmpCode() {
return EmpCode;
}
public void setEmpCode(String empCode) {
EmpCode = empCode;
}
public String getEmpName() {
return EmpName;
}
public void setEmpName(String empName) {
EmpName = empName;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
然后创建用户操作的业务层Service;由于这里主要是测试NOSQL的数据持久化,所以就忽略了对数据库持久化层(DAO)的操作。
userServiceImpl类:
/**
* 业务层接口实现
* @author leo
*
*/
public class UserServiceImpl implements IUserService {
private static final String cacheKey ="userEntity";
/**
* 缓存存储
*/
private RedisCacheStorageImpl<UserEntity> storageCache;
public void setStorageCache(RedisCacheStorageImpl<UserEntity> storageCache) {
this.storageCache = storageCache;
}
/**
* 新增
* @param entity
* @return
*/
@Override
public boolean addUserEntity(UserEntity entity) {
//非空
if(entity ==null || StringUtils.isEmpty(entity.getUserId())){
return false;
}
/**
* 做数据库持久化,这里就无需再申明了
*/
System.out.println("先插入数据库中,.........");
//然后接下来做非关系型数据库持久化
return storageCache.hset(cacheKey, entity.getUserId(), entity);
}
@Override
public boolean deleteUserEntity(UserEntity entity) {
return false;
}
/**
* 根据id 查询
* @return
*/
@Override
public UserEntity queryUserEntityByUserId(UserEntity userEntity) {
//非空
if(userEntity ==null || StringUtils.isEmpty(userEntity.getUserId())){
return null;
}
//先去缓存中查询 是否存在,不存在在查询
UserEntity reslut = storageCache.hget(cacheKey, userEntity.getUserId());
if(reslut!=null){
return reslut;
}else{
//查询数据库
System.out.println("查询数据库");
}
return null;
}
}
以及spring-bean.xml的配置对业务层的管理:
<!-- storge Cache 存储器-->
<bean id="storageCache" class="com.deppon.cache.storage.impl.RedisCacheStorageImpl">
<property name="redisClient" ref="redisClient" />
</bean>
<bean id="userServiceImpl" class="com.deppon.cache.service.impl.UserServiceImpl">
<property name="storageCache" ref="storageCache"/>
</bean>
(6).最后写个junit 测下,查看是否有没有插入到redis库中
public class TestUserServiceImpl {
/**
* 用户接口
*/
private IUserService userServiceImpl;
public void setUserServiceImpl(IUserService userServiceImpl) {
this.userServiceImpl = userServiceImpl;
}
@Before
public void setUp() throws Exception {
userServiceImpl = (IUserService) SpringTestHelper.get().getBeanByClass(UserServiceImpl.class);
}
@After
public void tearDown() throws Exception {
}
@Test
public void testAdd(){
UserEntity entity = new UserEntity();
entity.setUserId("000001");
entity.setEmpCode("130566");
entity.setEmpName("leonardo-zeng");
entity.setRole("Java Development Engineer");
entity.setTitle("PM");
boolean isTrue =userServiceImpl.addUserEntity(entity);
Assert.assertTrue(isTrue);
}
@Test
public void testQueryById(){
UserEntity entity = new UserEntity();
entity.setUserId("000001");
UserEntity userEntity =userServiceImpl.queryUserEntityByUserId(entity);
System.out.println(userEntity);
}
}
连接redis库,查询出来的确值在库中存在
redis 127.0.0.1:6379> hkeys "\"userEntity\""
1) "\"000001\""
redis 127.0.0.1:6379> hget "\"userEntity\"" "\"000001\""
"{\"@type\":\"com.deppon.cache.entity.UserEntity\",\"empCode\":\"130566\",\"empN
ame\":\"leonardo-zeng\",\"role\":\"Java Development Engineer\",\"title\":\"PM\",
\"userId\":\"000001\"}"
redis 127.0.0.1:6379>
整个demo就这样了