工欲善其事必先利其器;预备一下工具对于整个环境的整合有极大的帮助
- linux环境中单例redis服务搭建,参考博客 centos7自学之7-redis-4.0.1单例服务器搭建
- redisDesktopManage redis可视化工具安装
- idea开发工具
开始
现如今,越来越多的公司注重用户对网站访问速度的体验。而缓存技术的出现无疑很好的适用以上场景。
因此掌握一门缓存技术对一名IT男无疑是必要的。
创建springboot-redis项目
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--redis连接池-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--测试框架-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--json序列化-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!--自己封装的redis增删改查方法-->
<dependency>
<groupId>com.hsy.java</groupId>
<artifactId>java-util</artifactId>
</dependency>
创建redis配置文件
新建conf/redis.properties文件
#Matser的ip地址
redis.host=172.16.191.102
#端口号
redis.port=6379
#如果有密码
redis.password=123456
# 数据库索引
redis.database=0
#客户端超时时间单位是毫秒 默认是2000
redis.timeout=10000
#最大空闲数
redis.pool.maxIdle=300
#连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal
#redis.pool.maxActive=600
#控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
redis.pool.maxTotal=1000
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
redis.pool.maxWaitMillis=1000
#连接的最小空闲时间 默认1800000毫秒(30分钟)
redis.pool.minEvictableIdleTimeMillis=300000
#每次释放连接的最大数目,默认3
redis.pool.numTestsPerEvictionRun=1024
#逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
redis.pool.timeBetweenEvictionRunsMillis=30000
#是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
redis.pool.testOnBorrow=true
#在空闲时检查有效性, 默认false
redis.pool.testWhileIdle=true
新建RedisConfig.java
package com.hsy.springboot.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
/**
* @author heshiyuan
* @description <p></p>
* @path springboot/com.hsy.springboot.redis.config
* @date 2018/7/26 9:09
* @github http://github.com/shiyuan2he
* @email
* Copyright (c) 2018 shiyuan4work@sina.com All rights reserved.
* @price ¥5
*/
@Configuration
@PropertySource("classpath:config/redis.properties")
public class RedisConfig {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private Integer port;
@Value("${redis.password}")
private String password;
@Value("${redis.database}")
private Integer database;
@Value("${redis.timeout}")
private Integer timeout;
@Value("${redis.pool.maxIdle}")
private Integer maxIdle;
@Value("${redis.pool.maxTotal}")
private Integer maxTotal;
@Value("${redis.pool.maxWaitMillis}")
private Integer maxWaitMillis;
@Value("${redis.pool.minEvictableIdleTimeMillis}")
private Integer minEvictableIdleTimeMillis;
@Value("${redis.pool.numTestsPerEvictionRun}")
private Integer numTestsPerEvictionRun;
@Value("${redis.pool.timeBetweenEvictionRunsMillis}")
private long timeBetweenEvictionRunsMillis;
@Value("${redis.pool.testOnBorrow}")
private boolean testOnBorrow;
@Value("${redis.pool.testWhileIdle}")
private boolean testWhileIdle;
/**
* JedisPoolConfig 连接池
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大空闲数
jedisPoolConfig.setMaxIdle(maxIdle);
// 连接池的最大数据库连接数
jedisPoolConfig.setMaxTotal(maxTotal);
// 最大建立连接等待时间
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
// 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
// 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
jedisPoolConfig.setTestOnBorrow(testOnBorrow);
// 在空闲时检查有效性, 默认false
jedisPoolConfig.setTestWhileIdle(testWhileIdle);
return jedisPoolConfig;
}
/**
* 单机版配置
* @Title: JedisConnectionFactory
* @param @param jedisPoolConfig
* @param @return
* @return JedisConnectionFactory
* @autor lpl
* @date 2018年2月24日
* @throws
*/
@Bean
public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig){
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
jedisConnectionFactory.setUsePool(true);
//连接池
jedisConnectionFactory.setPoolConfig(jedisPoolConfig);
//IP地址
jedisConnectionFactory.setHostName(host);
//端口号
jedisConnectionFactory.setPort(port);
//如果Redis设置有密码
jedisConnectionFactory.setPassword(password);
// 设置数据库索引号
jedisConnectionFactory.setDatabase(database);
//客户端超时时间单位是毫秒
jedisConnectionFactory.setTimeout(timeout);
return jedisConnectionFactory;
}
/**
* 实例化 RedisTemplate 对象
*
* @return
*/
@Bean
public RedisTemplate<String, Object> functionDomainRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
return redisTemplate;
}
/**
* 设置数据存入 redis 的序列化方式,并开启事务
*
* @param redisTemplate
* @param factory
*/
private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
//如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// GenericJackson2JsonRedisSerializer序列化方式
//redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
//redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// Jackson2JsonRedisSerializer序列化方式
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//set value serializer
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
// 开启事务
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(factory);
redisTemplate.afterPropertiesSet();
}
}
创建入口类
@SpringBootApplication
public class SpringBootRedisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRedisApplication.class,args) ;
}
}
创建dao层数据接口文件
RedisRepository.java
@Repository(value = "redisRepository")
public class RedisRepository extends AbstractSpringRedisCacheEnhance{
@Autowired
RedisTemplate<String, Object> redisTemplate;
@Override
public StringRedisTemplate getStringRedisTemplate() {
return null;
}
@Override
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
}
AbstractSpringRedisCacheEnhance封装有crud方法,有上千行代码,就不贴在这里了,
有兴趣的可以去我github上fork。后面会附上源码地址
创建测试类
package com.hsy.springboot.redis;
import com.hsy.springboot.redis.dao.RedisRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author heshiyuan
* @description <p></p>
* @path spring/com.hsy.spring.redis.dao
* @date 2018/7/23 18:42
* @github http://github.com/shiyuan2he
* @email
* Copyright (c) 2018 shiyuan4work@sina.com All rights reserved.
* @price ¥5
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootRedisApplication.class)
public class RedisRepositoryTest {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired private RedisRepository redisRepository;
public Map<String, Object> generateMap(){
Map<String, Object> returnMap = new HashMap<>();
returnMap.put("aa", "aa");
Map<String, Object> innerMap = new HashMap<>();
innerMap.put("ss", 3);
innerMap.put("rr",false);
innerMap.put("tt","中文");
returnMap.put("bb", innerMap);
returnMap.put("cc", 1.000);
returnMap.put("dd", true);
returnMap.put("ee", 2);
return returnMap;
}
public List<Map<String, Object>> generateList(){
List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(generateMap());
}
return list;
}
@Test
public void clear(){
redisRepository.clear();
}
@Test
public void testSet(){
redisRepository.valueSet("name", "robot");
redisRepository.valueSet("name2", "robot", 1600, TimeUnit.SECONDS);
redisRepository.valueSet("set:map", generateMap());
redisRepository.valueSet("set:map", generateMap(), 1600, TimeUnit.SECONDS);
redisRepository.valueSet("set:list", generateList());
redisRepository.valueSet("set:list", generateList(), 1600, TimeUnit.SECONDS);
}
@Test
public void testGet(){
logger.info("{}", redisRepository.valueGet("name", false));
logger.info("{}", redisRepository.valueGet("name2", true));
logger.info("{}", redisRepository.valueGet("set:map", false));
logger.info("{}", redisRepository.valueGet("set:map", true));
logger.info("{}", redisRepository.valueGet("set:list", false));
logger.info("{}", redisRepository.valueGet("set:list", true));
//logger.info("{}", redisRepository.getAndSet("name", "new value",false));
//logger.info("{}", redisRepository.getAndSet("name", "new value",true));
}
@Test
public void testIncrement(){
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.valueIncrement("mobile:15911111111", 1l, 60, TimeUnit.MINUTES));
logger.info("{}", redisRepository.valueIncrement("tel:15911111111", 1.0, 70, TimeUnit.MINUTES));
}
}
@Test
public void testSetArray(){
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.setAdd("set:array1",i));
}
for (int i = 5; i < 20; i++) {
logger.info("{}", redisRepository.setAdd("set:array1",i));
logger.info("{}", redisRepository.setAdd("set:array2",i));
}
//logger.info("{}", redisRepository.setPop("set:array"));
logger.info("{}", redisRepository.setDifference("set:array1","set:array2"));
logger.info("{}", redisRepository.setDifferenceAndStore("set:array1","set:array2", "set:array3"));
logger.info("{}", redisRepository.setAdd("set:add:map",generateMap()));
logger.info("{}", redisRepository.setAdd("set:add:list",generateList()));
logger.info("{}", redisRepository.setPop("set:add:map"));
logger.info("{}", redisRepository.setPop("set:add:list"));
}
@Test
public void testList(){
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.listLeftPush("list:lilo:list", generateList()));
logger.info("{}", redisRepository.listLeftPush("list:liro:list", generateList()));
logger.info("{}", redisRepository.listRightPush("list:rilo:list", generateList()));
logger.info("{}", redisRepository.listRightPush("list:riro:list", generateList()));
}
for (int i = 0; i < 5; i++) {
logger.info("{}", redisRepository.listLeftPop("list:lilo:list"));
logger.info("{}", redisRepository.listRightPop("list:liro:list"));
logger.info("{}", redisRepository.listLeftPop("list:rilo:list"));
logger.info("{}", redisRepository.listRightPop("list:riro:list"));
}
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.listLeftPush("list:lilo:map", generateMap()));
logger.info("{}", redisRepository.listLeftPush("list:liro:map", generateMap()));
logger.info("{}", redisRepository.listRightPush("list:rilo:map", generateMap()));
logger.info("{}", redisRepository.listRightPush("list:riro:map", generateMap()));
}
for (int i = 0; i < 5; i++) {
logger.info("{}", redisRepository.listLeftPop("list:lilo:map"));
logger.info("{}", redisRepository.listRightPop("list:liro:map"));
logger.info("{}", redisRepository.listLeftPop("list:rilo:map"));
logger.info("{}", redisRepository.listRightPop("list:riro:map"));
}
}
@Test
public void testZSet(){
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.zSetAdd("zset:map", generateMap(), i));
}
redisRepository.zSetIncrementScore("zset:Map", "4", 30);
}
@Test
public void testHash(){
for (int i = 0; i < 10; i++) {
redisRepository.hashPut("hash:map", String.valueOf(i), generateMap());
logger.info("{}", redisRepository.hashGet("hash:map", String.valueOf(i)));
}
for (int i = 0; i < 10; i++) {
redisRepository.hashPut("hash:list", String.valueOf(i), generateList());
logger.info("{}", redisRepository.hashGet("hash:list", String.valueOf(i)));
}
}
}
扩展
底层redis增删改查封装好之后,就很好扩展,如果想使用StringRedisTemplate,只需要简单的继承即可。
新建StringRedisRepository.java
@Repository(value = "stringRedisRepository")
public class StringRedisRepository extends AbstractSpringStringRedisCacheEnhance {
@Autowired StringRedisTemplate stringRedisTemplate;
@Override
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
@Override
public RedisTemplate<String, Object> getRedisTemplate() {
return null;
}
}
测试类
/**
* @author heshiyuan
* @description <p></p>
* @path spring/com.hsy.spring.redis.dao
* @date 2018/7/24 10:13
* @github http://github.com/shiyuan2he
* @email shiyuan4work@sina.com
* Copyright (c) 2018 shiyuan4work@sina.com All rights reserved.
* @price ¥5 微信:hewei1109
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootRedisApplication.class)
public class StringRedisRepositoryTest {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired private StringRedisRepository stringRedisRepository;
@Test
public void testSet(){
stringRedisRepository.set("name", "robot");
stringRedisRepository.set("name", "robot", 60);
stringRedisRepository.set("name2", "robot", 1600, TimeUnit.SECONDS);
}
@Test
public void testGet(){
logger.info(stringRedisRepository.get("name", false));
logger.info(stringRedisRepository.get("name", true));
logger.info(stringRedisRepository.getAndSet("name", "new value",false));
logger.info(stringRedisRepository.getAndSet("name", "new value",true));
}
@Test
public void testIncrement(){
for (int i = 0; i < 10; i++) {
logger.info("{}", stringRedisRepository.increment("mobile:15911111111", 1l, 60, TimeUnit.MINUTES));
logger.info("{}", stringRedisRepository.increment("tel:15911111111", 1.0, 70, TimeUnit.MINUTES));
}
}
@Test
public void testSetArray(){
for (int i = 0; i < 10; i++) {
logger.info("{}", stringRedisRepository.addSet("set:array1",String.valueOf(i)));
}
for (int i = 5; i < 20; i++) {
logger.info("{}", stringRedisRepository.addSet("set:array1",String.valueOf(i)));
logger.info("{}", stringRedisRepository.addSet("set:array2",String.valueOf(i)));
}
//logger.info("{}", stringRedisRepository.popSet("set:array"));
logger.info("{}", stringRedisRepository.difference("set:array1","set:array2"));
logger.info("{}", stringRedisRepository.differenceAndStore("set:array1","set:array2", "set:array3"));
}
@Test
public void testList(){
for (int i = 0; i < 10; i++) {
logger.info("{}", stringRedisRepository.leftPush("list:lilo", String.valueOf(i)));
logger.info("{}", stringRedisRepository.leftPush("list:liro", String.valueOf(i)));
logger.info("{}", stringRedisRepository.rightPush("list:rilo", String.valueOf(i)));
logger.info("{}", stringRedisRepository.rightPush("list:riro", String.valueOf(i)));
}
for (int i = 0; i < 5; i++) {
logger.info("{}", stringRedisRepository.leftPop("list:lilo"));
logger.info("{}", stringRedisRepository.rightPop("list:liro"));
logger.info("{}", stringRedisRepository.leftPop("list:rilo"));
logger.info("{}", stringRedisRepository.rightPop("list:riro"));
}
}
@Test
public void testZSet(){
/* for (int i = 0; i < 10; i++) {
logger.info("{}", stringRedisRepository.addZSet("zset", String.valueOf(i), i+1));
}*/
stringRedisRepository.incrementScore("zset", "4", 30);
}
@Test
public void testHash(){
for (int i = 0; i < 10; i++) {
stringRedisRepository.put4Hash("hash", String.valueOf(i), String.valueOf(i));
logger.info("{}", stringRedisRepository.get("hash", String.valueOf(i)));
}
}
}
注意:
本文介绍StringRedisTemplate、RedisTemplate这两个模板来介绍,其中StringRedisTemplate继承自RedisTemplate,只能操作键值都是String类型的数据。在实际开发中建议使用RedisTemplate
源码