Redis操作
依赖包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
Application配置
# Redis 数据库索引(默认为 0)
spring.redis.database=0
# Redis 服务器器地址
spring.redis.host=localhost
# Redis 服务器器连接端⼝口
spring.redis.port=6379
# Redis 服务器器连接密码(默认为空)
spring.redis.password=
# 连接池最⼤大连接数(使⽤用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最⼤大阻塞等待时间(使⽤用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最⼤大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最⼩小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
Spring Boot 默认⽀支持 Lettuce 连接池
测试使用
直接上代码:
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestRedisTemplate {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testString() {
redisTemplate.opsForValue().set("hiki", "knight");
Assert.assertEquals("knight", redisTemplate.opsForValue().get("hiki"));
}
}
如果发现private RedisTemplate redisTemplate;
报错:
Could not autowire. There is more than one bean of 'RedisTemplate' type.Beans:redisTemplate (RedisAutoConfiguration.class)stringRedisTemplate (RedisAutoConfiguration.class)
可能是写成了redistemplate
,说明要规范。或者我偶然在网上看到别的解决方案:
在一个配置类中定义这个类即可修复:
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
实体
Redis支持Pojo类型
public void testObj(){
User user=new User("hiki@cool.com", "good", "shoot", "knight","2019");
ValueOperations<String, User> operations=redisTemplate.opsForValue();
operations.set("com.hiki", user);
User u=operations.get("com.hiki");
System.out.println("user: "+u.toString());
}
超时
就是每个数据的超时时间,时间到了会自动删除。直接上代码::
ValueOperations<String, User> operations=redisTemplate.opsForValue();
operations.set("hiki", user,100,TimeUnit.MILLISECONDS);//单位毫秒
删除
@Test
public void testDelete() {
ValueOperations<String, User> operations=redisTemplate.opsForValue();
redisTemplate.opsForValue().set("deletekey", "hiki");
redisTemplate.delete("deletekey");
boolean exists=redisTemplate.hasKey("deletekey");
if(exists){
System.out.println("exists is true");
}else{
System.out.println("exists is false");
}
}
Hash(哈希)
Hash Set 就在哈希表 Key中的域(Field)的值设为value。如果Key不存在,一个新的哈希表被创建并进行 HSET 操作;如果域(field)已经存在于哈希表中,旧值将被覆盖。
@Test
public void testHash() {
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put("hash","you","you");
String value=(String) hash.get("hash","you");
System.out.println("hash value :"+value);
}
第一个为可以,第二个为field,第三个为存储的值。也就是类似二维数组,仔细想想就是hash的结构。
List
使用List可以轻松实现队列,典型应用场景是消息队列,利用Push、Pop操作。
@Test
public void testList() {
ListOperations<String, String> list = redisTemplate.opsForList();
list.leftPush("list","hiki");
list.leftPush("list","px");
list.leftPush("list","knight");
String value=(String)list.leftPop("list");
System.out.println("list value :"+value.toString());
}
结果:
list value :knight
这不是栈么。。。
上面的例子是左插,还可以右插(右插的话应该就是队列了),Redis是双向链表,因此带来了额外的内存开销
Set
与List类似,但是自动排重,Set 可以判断某个成员是否在Set集合内的重要接口。
@Test
public void testSet() {
String key="set";
SetOperations<String, String> set = redisTemplate.opsForSet();
set.add(key,"hiki");
set.add(key,"knight");
set.add(key,"knight");
set.add(key,"cool");
Set<String> values=set.members(key);
for (String v:values){
System.out.println("set value :"+v);
}
}
结果:
set value :hiki
set value :knight
set value :cool
difference方法
SetOperations<String, String> set = redisTemplate.opsForSet();
String key1="setMore1";
String key2="setMore2";
set.add(key1,"hiki");
set.add(key1,"cool");
set.add(key1,"knight");
set.add(key1,"knight");
set.add(key2,"xxx");
set.add(key2,"knight");
Set<String> diffs=set.difference(key1,key2);
for (String v:diffs){
System.out.println("diffs set value :"+v);
}
结果:
diffs set value :hiki
diffs set value :cool
根据上面这个例⼦子可以看出,difference()函数会把key1中不同于key2的数据对比出来,这个特性适合我们在金融场景中对账的时候使用。
unions方法
将两个集合合起来,不贴代码了
Set 的内部实现是一个 Value 永远为 null 的 HashMap,实际就是通过计算 Hash 的方式来快速排重,这也是 Set 能提供判断一个成员是否在集合内的原因。
ZSet
ZSet是自动有序的,用户可以通过优先级的参数(Score)来为成员排序
@Test
public void testZset(){
String key="zset";
redisTemplate.delete(key);
ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
zset.add(key,"it",1);
zset.add(key,"you",6);
zset.add(key,"know",4);
zset.add(key,"neo",3);
Set<String> zsets=zset.range(key,0,3);
for (String v:zsets){
System.out.println("zset value :"+v);
}
Set<String> zsetB=zset.rangeByScore(key,0,3);
for (String v:zsetB){
System.out.println("zsetB value :"+v);
}
}
结果:
zset value :it
zset value :neo
zset value :know
zset value :you
zsetB value :it
zsetB value :neo
Redis Sorted Set 的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap 里放的是成员到Score的映射,而跳跃表⾥存放的是所有的成员,排序依据是HashMap 里存的 Score,⽤用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
封装
实际使用时,一般将redisTemplate封装到一个类中使用,例如:
@Service
public class RedisService {
@Autowired
private RedisTemplate redisTemplate;
}
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
logger.error("set error: key {}, value {}",key,value,e);
}
return result;
}
项目代码
github: https://github.com/Hikiy
作者:Hiki
创建日期:2019.04.12
更新日期:2019.05.15
(转载本站文章请注明作者和出处 Hiki)