Redis是KV内存数据库,支持很多数据结构,具体如下面之前写过的,也可以自行google
Spring对Redis操作的支持,基本也和JDBC,MongoDB类似,通过Spring Data Redis,具体有
1、客户端支持,Jedis和Lettuce
2、RedisTemplate
3、Repository支持
测试一下通过Jedis来操作数据库,而Jedis非线程安全,所以一般通过JedisPool线程安全的连接池创建一些Jedis实例,要用的时候就从池子里拿Jedis实例来进行redis操作,用完后归还给JedisPool
可以简单看下JedisPool,它继承了JedisPoolAbstract
public class JedisPool extends JedisPoolAbstract {
JedisPoolAbstract继承了泛型Pool
public class JedisPoolAbstract extends Pool<Jedis> {
具体类的定义里
public abstract class Pool<T> implements Closeable {
从下面可以看出来最终调用getResource()方法,就可以从池子里获取一个Jedis对象,进而对redis进行各种操作
public T getResource() {
try {
return internalPool.borrowObject();
} catch (NoSuchElementException nse) {
if (null == nse.getCause()) { // The exception was caused by an exhausted pool
throw new JedisExhaustedPoolException(
"Could not get a resource since the pool is exhausted", nse);
}
// Otherwise, the exception was caused by the implemented activateObject() or ValidateObject()
throw new JedisException("Could not get a resource from the pool", nse);
} catch (Exception e) {
throw new JedisConnectionException("Could not get a resource from the pool", e);
}
}
因此,要想操作Redis,只需要配置好JedisPool的Bean就行了
具体配置类如下,参考JedisPool的构造方法即可配置
package com.lihuia.redis.jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
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;
/**
* Copyright (C), 2018-2019
* FileName: JedisConfig
* Author: lihui
* Date: 2019/11/12
*/
@PropertySource(value = {"classpath:config/redis.properties"})
@Configuration
public class JedisConfig {
@Bean
public JedisPoolConfig jedisPoolConfig() {
return new JedisPoolConfig();
}
@Bean(destroyMethod = "close")
public JedisPool jedisPool(@Value("${redis.host}") String host) {
return new JedisPool(jedisPoolConfig(), host);
}
}
这里redis连接配置在redis.properties里,通过@PropertySource注解指明,内容如下
redis.host=localhost
同时Bean添加一个属性方法,在关闭这个Bean之前,close关闭连接
而JedisPoolConfig里配置了一些池子的基本属性
package redis.clients.jedis;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
public class JedisPoolConfig extends GenericObjectPoolConfig {
public JedisPoolConfig() {
// defaults to make your life with connection pool easier :)
setTestWhileIdle(true);
setMinEvictableIdleTimeMillis(60000);
setTimeBetweenEvictionRunsMillis(30000);
setNumTestsPerEvictionRun(-1);
}
}
有了这些之后,先本地起一个redis-server,然后以最简单的String类型为例,其他数据类型也一样
127.0.0.1:6379> set one 1 OK 127.0.0.1:6379> get one "1" 127.0.0.1:6379>
测试类就比较容易了
package com.lihuia.redis.jedis;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
/**
* Copyright (C), 2018-2019
* FileName: NumTest
* Author: lihui
* Date: 2019/11/12
*/
@ContextConfiguration(classes = {JedisConfig.class})
@Slf4j
public class JedisTest extends AbstractTestNGSpringContextTests {
@Resource
private JedisPool jedisPool;
@Test(description = "字符串类型")
public void stringTest() {
try (Jedis jedis = jedisPool.getResource()) {
log.info("String: one => " + jedis.get("one"));
}
}
}
执行结果如下
[main] INFO com.lihuia.redis.jedis.JedisTest - String: one => 1
再来试试RedisTemplate的操作方法,和之前JdbcTemplate和MongoTemplate一样,关键的是Bean的配置,配置类如下
package com.lihuia.redis.template;
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.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
/**
* Copyright (C), 2018-2019
* FileName: RedisConfig
* Author: lihui
* Date: 2019/11/12
*/
@PropertySource(value = {"classpath:config/redis.properties"})
@Configuration
public class RedisConfig {
@Value("${redis.host}")
private String hostname;
@Bean
public RedisStandaloneConfiguration redisStandaloneConfiguration() {
return new RedisStandaloneConfiguration(hostname);
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new JedisConnectionFactory(redisStandaloneConfiguration());
}
@Bean
public RedisTemplate redisTemplate() {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
这里配置RedisTemplate类的时候,并没有指明泛型KV的类型,可以进行操作的时候再进行类型转换
测试类如下,基本上每种数据类型的操作都可以他通过RedisTemplate.opsForXXX来完成
package com.lihuia.redis.template;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.Test;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
/**
* Copyright (C), 2018-2019
* FileName: NumTest
* Author: lihui
* Date: 2019/11/12
*/
@ContextConfiguration(classes = {RedisConfig.class})
@Slf4j
public class TemplateTest extends AbstractTestNGSpringContextTests {
@Resource
private RedisTemplate redisTemplate;
@Test(description = "字符串校验")
public void stringTest() {
log.info((String) redisTemplate.opsForValue().get("one"));
}
}
但是,这里的测试执行结果是null
[main] INFO com.lihuia.redis.template.TemplateTest - null
原因是对于RedisTemplate,存和取都是将数据序列化为字节数组后,存到Redis,而读取也必须是读取字节数组,而显然我刚通过redis-cli写入的{“one”:”1”}是完全可以读取的,因此通过RedisTemplate是无法读取的
想证明这一点很容易,通过调用redisTemplate.opsForValue().set()方法插入数据,这肯定是序列化了的,再get看结果
package com.lihuia.redis.template;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.Test;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
/**
* Copyright (C), 2018-2019
* FileName: NumTest
* Author: lihui
* Date: 2019/11/12
*/
@ContextConfiguration(classes = {RedisConfig.class})
@Slf4j
public class TemplateTest extends AbstractTestNGSpringContextTests {
@Resource
private RedisTemplate redisTemplate;
@Test(description = "字符串校验")
public void stringTest() {
redisTemplate.opsForValue().set("three", "3");
log.info((String) redisTemplate.opsForValue().get("three"));
}
}
测试的结果,这样就对了
[main] INFO com.lihuia.redis.template.TemplateTest - 3
而对于字符串类型,有一个专门的stringRedisTemplate来操作,十分方便,Bean如下
@Bean
public StringRedisTemplate stringRedisTemplate() {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory());
return stringRedisTemplate;
}
然后对于可见的{“one”:”1”}也是可以正常获取的
package com.lihuia.redis.template;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.Test;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
/**
* Copyright (C), 2018-2019
* FileName: NumTest
* Author: lihui
* Date: 2019/11/12
*/
@ContextConfiguration(classes = {RedisConfig.class})
@Slf4j
public class TemplateTest extends AbstractTestNGSpringContextTests {
@Resource
private RedisTemplate redisTemplate;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test(description = "字符串校验")
public void stringTest() {
log.info(stringRedisTemplate.opsForValue().get("one"));
}
}
RedisTemplate和StringRedisTemplate他们两的序列化类型不太一样
RedisTemplate使用JdkSerializationRedisSerializer序列化对象 StringRedisTemplate使用StringRedisSerializer序列化
因此,对于操作redis数据:
1、各自只能管理各自操作的数据,比如RedisTemplate写的,就不能用StringRedisTemplate来读取
2、如果处理的是Redis里的String类型,那就直接用StringRedisTemplate操作即可
3、如果处理的是Redis里的其它对象,可以用RedisTemplate来操作
4、如果通过客户端可以读取,或者获取的是NULL,那么可以用StringRedisTemplate来操作
最后测试一下操作对象
定义一个User类,序列化不要丢了
package com.lihuia.redis.template;
import java.io.Serializable;
import lombok.Builder;
/**
* Copyright (C), 2018-2019
* FileName: Num
* Author: lihui
* Date: 2019/11/12
*/
@Builder
public class User implements Serializable {
private static final long serialVersionUID = 2182129585108022309L;
private int age;
private String phone;
@Override
public String toString() {
return "age=" + age + ", phone=" + phone;
}
}
测试类,泛型RedisTemplate<String, User>来操作
package com.lihuia.redis.template;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.Test;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
/**
* Copyright (C), 2018-2019
* FileName: NumTest
* Author: lihui
* Date: 2019/11/12
*/
@ContextConfiguration(classes = {RedisConfig.class})
@Slf4j
public class TemplateTest extends AbstractTestNGSpringContextTests {
@Resource
private RedisTemplate<String, User> redisTemplate;
@Test(description = "对象校验")
public void redisTest() {
redisTemplate.opsForValue().set("lihui", User.builder().age(18).phone("17777777777").build());
redisTemplate.opsForValue().set("lilei", User.builder().age(19).phone("18888888888").build());
log.info(redisTemplate.opsForValue().get("lihui").toString());
log.info(redisTemplate.opsForValue().get("lilei").toString());
}
}
测试结果如下
[main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection. [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection. [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection. [main] INFO com.lihuia.redis.template.TemplateTest - age=18, phone=17777777777 [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Opening RedisConnection [main] DEBUG org.springframework.data.redis.core.RedisConnectionUtils - Closing Redis Connection. [main] INFO com.lihuia.redis.template.TemplateTest - age=19, phone=18888888888
Repository相关的就不试了,OVER