三.SSM项目-redis缓存策略和配置实现
距离上两篇文章已过去蛮久了,为了响应各位网友的需求,最近把这个系列重新整理下。如有不足之处,请指正。本章将实现redis缓存策略和Spring集成redis配置。
1. Redis简单介绍
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sortedset --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
----摘自百度百科
总结:
1.1 Redis是一个key-value存储系统,支持多种存储结构,如String,Hash,list,zset等;
1.2 Redis采用内存中数据集的形式,因此读写性能优异;
1.3 Redis支持数据持久化,支持AOF和RDB两种持久化方式;
1.4 Redis类似mysql可以进行主从复制,可以实现读写分离;
1.5 Redis由于是内存中数据集存储的,故对内存的要求较高,对海量数据处理有限制;
1.6 Redis主从复制时,由于宕机或其他情况一起,导致最后部分数据可能丢失。
2. Redis缓存策略
Redis和数据库结合使用,使用策略如下:
2.1 读取数据
2.2 更新数据—常用数据,变动性不强,并发不高
2.3 更新数据—并发较高
3. Spring集成redis
3.1 applicationContext-redis.xml
spring与redis集成配置文件
<?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"
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-4.1.xsd">
<!-- 连接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="30" />
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10" />
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="1024" />
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="true" />
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false" />
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="${redis.ip}"></constructor-arg>
<constructor-arg name="port" value="${redis.port}"></constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean>
</beans>
3.2 redisDao接口和实现
简单通过redis实现增删改查
package com.ssm.manager.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import redis.clients.jedis.JedisPool;
@Repository("redisDao")
public class RedisDaoImpl implements RedisDao {
@Autowired
private JedisPool jedisPool;
@Override
public String get(String key) {
return jedisPool.getResource().get(key);
}
@Override
public String set(String key, String value) {
return jedisPool.getResource().set(key,value);
}
@Override
public String hget(String hkey, String key) {
return jedisPool.getResource().hget(hkey, key);
}
@Override
public long hset(String hkey, String key, String value) {
return jedisPool.getResource().hset(hkey, key,value);
}
}
3.3 UserServiceImpl实现
实现User业务,先查redis,如果不存在从数据库获取,然后把相关信息写入到redis
package com.ssm.manager.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ssm.commons.JacksonUtils;
import com.ssm.manager.dao.RedisDao;
import com.ssm.manager.mapper.UserMapper;
import com.ssm.manager.pojo.User;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RedisDao redisDao;
@Override
public List<User> getUsers() {
return userMapper.getUsers();
}
@Override
public void insertUser(User user) {
userMapper.insertUser(user);
String userJson = redisDao.get("user_" + user.getId());
if(StringUtils.isEmpty(userJson)){
redisDao.set("user_" + user.getId(), JacksonUtils.objectToJson(user));
}
}
@Override
public User getUserById(String id) {
String userJson = redisDao.get("user_" + id);
User user = null;
if(StringUtils.isEmpty(userJson)){
user = userMapper.getUserById(id);
//不存在,设置
if(user != null)
redisDao.set("user_" + id, JacksonUtils.objectToJson(user));
}else{
user = JacksonUtils.jsonToPojo(userJson, User.class);
}
return user;
}
}
4. 单元测试
package com.ssm.test;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ssm.manager.pojo.User;
import com.ssm.manager.service.UserService;
public class ssmTest {
private ApplicationContext ctx = null;
private UserService userService = null;
@Before
public void init()
{
ctx = new ClassPathXmlApplicationContext("spring/applicationContext-service.xml");
userService = ctx.getBean(UserService.class);
}
@Test
public void testGetUsers(){
List<User> users = userService.getUsers();
System.out.println(users);
}
@Test
public void testInsertUser(){
User user = new User();
user.setPassword("123");
user.setUserName("ssm1111");
userService.insertUser(user);
}
@Test
public void testGetUserById(){
String id="4";
System.out.println(userService.getUserById(id));
}
}
5. 总结
本章简单的介绍Spring与redis框架jedis集成。如果需要也可以考虑通过spring data redis去集成.
后续本来也会通过springboot+spring data redis的实例来实现redis。