目录
1.Redis简介
1.1 NoSQL
NoSQL,泛指非关系型的数据库,NoSQL即Not-Only SQL,它可以作为关系型数据库的良好补充
1.2 NoSQL的类别
- 键值(Key-Value)存储数据库
- 列存储数据库
- 文档型数据库
- 图形(Graph)数据库
1.3 Redis是什么
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:
字符串类型
散列类型
列表类型
集合类型
有序集合类型
Redis 与其他 key - value 缓存产品有以下三个特点:
-
Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
-
Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
-
Redis支持数据的备份,即master-slave模式的数据备份。
Redis 提供的API支持:C、C++、C#、Clojure、Java、JavaScript、Lua、PHP、Python、Ruby、Go、Scala、Perl等多种语言。
1.4 Redis优缺点
1.Redis优势
对数据高并发读写(基于内存)
对海量数据的高效率存储和访问(基于内存)
对数据的可扩展性和高可用性
垂直扩展:提升硬件
水平扩展:集群
2.Redis缺点
redis(ACID处理非常简单)无法做到太复杂的关系数据库模型
2.Redis常用命令
2.1 String类型
String 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字,是包含很多种类型的特殊类型,并且是二进制安全的。比如序列化的对象进行存储,比如一张图片进行二进制存储,比如一个简单的字符串,数值等等。
设值:set name zhangsan (说明:多次设置name会覆盖)
命令:
setnx name lx: (not exist) 如果name不存在,则设值。如果name存在,则不设值并返回0;
setex name 10 lx :(expired) 设置name的值为lx,过期时间为10秒,10秒后name清除(key也清除)
setrange string range value 替换字符串
取值: get name
删值:del name
批量写:mset k1 v1 k2 v2 …
批量读:mget k1 k2 k3
一次性设值和读取(返回旧值,写上新值):getset name lx
数值类型自增减:incr,decr,incrby,decrby
字符串拼接:append key value
字符串长度:strlen key
2.2 Hash类型
Hash类型是String类型的field和value的映射表,或者说是一个String集合。它特别适合存储对象,相比较而言,将一个对象类型存储在Hash类型要存储在String类型里占用更少的内存空间,并方整个对象的存取。
设值:hset hashname field value(hset是设值命令,hashname是集合名字,field是字段名,value是值)
取值:hget hashname field
批量设置:hmset hashname field1 value1 field2 value2 ….
批量取值:hmget hashname field1 field2 …
hsetnx:和setnx大同小异
hincrby:指定字段增加指定值
hexists:是否存在key,如果存在返回,不存在返回0
删除:hdel 删除指定的hash的field
hlen:返回hash集合里的所有的键数值(size)
hkeys:返回hash里所有的字段
hvals:返回hash的所有value
hgetall:返回hash里所有的key和value
2.3 List类型
List类型是一个链表结构的集合,其主要功能有push、pop、获取元素等。更详细的说,List类型是一个双端链表的节后,我们可以通过相关的操作进行集合的头部或者尾部添加和删除元素,List的设计非常简单精巧,即可以作为栈,又可以作为队列,满足绝大多数的需求。
lpush:从头部加入元素(栈,先进后出)
rpush:从尾部加入元素(队列,先进先出)
linsert:插入元素
lrange:获取指定索引内的所有元素
lset:将制定下表的元素替换掉
lrem:删除元素,移除n个,返回删除的个数n
ltrim:保留制定key的值范围内的数据
lpop:从list的头部删除元素,并返回删除元素。
rpop:从list的尾部删除元素,并返回删除元素
rpoplpush list1 list2:从list1尾部删除元素,并将被移除的元素添加到list2的头部,返回被移除的元素,可以实现MQ
llen:返回元素个数
lindex:返回名称为key的list中index位置的元素
2.4 Set类型
set集合是string类型的无序集合,set是通过hashtable实现的,对集合我们可以取交集、并集、差集
sadd:向名称为key的set中添加元素,set集合不允许重复元素。
smembers:查看set集合中的元素。
srem:删除set集合的元素
spop:随机返回删除的key
sdiff:返回两个集合的不同元素(哪个集合在前面就以哪个集合为标准)
sdiffstore:将返回的不同元素,存储到另一个集合里
sdiffstore set4 set2 set3 将set2 set3的比较结果保存到set4中
sinter:取交集
sinterstore:取交集后保存
sunion:取并集
sunionstore:取并集后保存
smove:从一个set集合移动到另一个set集合里
scard:查看集合里的元素个数
sismember:判断某个元素是否为集合中的元素,是,返回1。不是,返回0。
srandmember:随机返回一个元素
2.5 Zset
有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zadd:向有序集合中添加一个元素,该元素如果存在则更新顺序,如果分值相同元素不同会同时存在两个元素。
zrem :删除zset名称key中的member元素
zrank 返回有序集合中指定成员的索引(从小到大排序)
zrevrank 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
zcard 返回集合里所有元素的个数
zcount 返回集合中score在给定区间中的数量
zincrby key increment member: 有序集合中对指定成员的分数加上增量 increment
zrangebyscore key min max [WITHSCORES] [LIMIT] :通过分数返回有序集合指定区间内的成员
zremrangebyrank key start stop :移除有序集合中给定的排名区间的所有成员
zremrangebyscore key min max:移除有序集合中给定的分数区间的所有成员
3.使用
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
/*
目前为止Redis支持的键值数据类型如下:
字符串类型
散列类型
列表类型
集合类型
有序集合类型*/
@Autowired
RedisTemplate redisTemplate;
//1.字符串类型 String
@Test
public void testString(){
//存值
redisTemplate.opsForValue().set("name","张三");
//根据key(name)查询
Object name = redisTemplate.opsForValue().get("name");
//10s后删除key(name)的值
redisTemplate.expire("name",10l, TimeUnit.SECONDS);
System.out.println("name======"+name);
}
//2.散列类型 Hash
@Test
public void testHash(){
//插入
// redisTemplate.opsForHash().put("user","name","张三");
// redisTemplate.opsForHash().put("user","age","18");
// redisTemplate.opsForHash().put("user","sex","男");
//用map方式插入
Map map=new HashMap<>();
map.put("name","李四");
map.put("age",18);
map.put("sex","女");
redisTemplate.opsForHash().putAll("user1",map);
//查询某个字段
Object o = redisTemplate.opsForHash().get("user", "age");
System.out.println("年龄为====="+ o);
//获取全部字段
List user = redisTemplate.opsForHash().values("user");
System.out.println(user);
}
//3.列表类型 List
@Test
public void testList(){
//从左插入
redisTemplate.opsForList().leftPush("list1","6666");
redisTemplate.opsForList().leftPush("list1","7777");
redisTemplate.opsForList().leftPush("list1","888");
redisTemplate.opsForList().leftPush("list1","999");
//从右插入
redisTemplate.opsForList().rightPush("list1","aaaa");
redisTemplate.opsForList().rightPush("list1","bbb");
redisTemplate.opsForList().rightPush("list1","ccc");
redisTemplate.opsForList().rightPush("list1","ddd");
redisTemplate.opsForList().rightPush("list1","eee");
List list1 = redisTemplate.opsForList().range("list1", 0, -1);
System.out.println(list1);
}
//4.集合类型 set 无序不重复
@Test
public void testSet(){
redisTemplate.opsForSet().add("zt1","aaaa");
redisTemplate.opsForSet().add("zt1","bbb");
redisTemplate.opsForSet().add("zt1","ccc");
redisTemplate.opsForSet().add("zt1","ddd");
redisTemplate.opsForSet().add("zt1","eee");
redisTemplate.opsForSet().add("zt1","fff");
redisTemplate.opsForSet().add("zt1","aaaa");
Set zt1 = redisTemplate.opsForSet().members("zt1");
System.out.println(zt1);
}
//5.有序集合类型 Zset 有序不重复
@Test
public void testZset(){
redisTemplate.opsForZSet().add("zset","aaa",1);
redisTemplate.opsForZSet().add("zset","bbb",0.5);
redisTemplate.opsForZSet().add("zset","ccc",1.5);
redisTemplate.opsForZSet().add("zset","ddd",2);
//满足条件的个数
Long zset = redisTemplate.opsForZSet().count("zset", 0.2, 1);
System.out.println(zset);
//查看所有 分数由低到高
Set zset1 = redisTemplate.opsForZSet().range("zset", 0, -1);
System.out.println(zset1);
//反转输出所有
Set zset2 = redisTemplate.opsForZSet().reverseRange("zset", 0, -1);
System.out.println(zset2);
}
}
4.实际应用
4.1 导入config
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
//使用fastjson序列化
Jackson2JsonRedisSerializer fastJsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(fastJsonRedisSerializer);
template.setHashValueSerializer(fastJsonRedisSerializer);
// key的序列化采用StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
4.2 应用
@Service
public class TeacherServiceImpl implements TeacherService {
@Autowired
TeacherRepository teacherRepository;
@Autowired
RedisTemplate redisTemplate;
@Override
public List<TbTeacher> findAll() {
//使用redis进行优化
List<TbTeacher> list=null;
Boolean teacher_1 = redisTemplate.hasKey("teacher_1");
if(teacher_1){
System.out.println("从redis中进行查询");
List teacher_11 = (List)redisTemplate.opsForValue().get("teacher_1");
list=teacher_11;
}else{
System.out.println("从数据库中进行查询");
list=teacherRepository.findAll();
redisTemplate.opsForValue().set("teacher_1",list);
}
return list;
}
}
第一次会从数据库查询,第二次就会在Redis中查询,如果数据库更新Redis更新