Redis
Redis简介
非关系型数据库,灵活、存储速度快。
基于内存进行存储,支持key-value的存储形式,底层使用c语言编写的。
是单线程的,基于内存的操作,所以CPU不是Redis的瓶颈,Redis的瓶颈是机器的内存的大小和网络带宽。单线程可以避免不必要的上下文切换和竞争条件,也不存在多进程或多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁的操作,没有因为可能出现死锁而导致的性能消耗。
Redis三大特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。(持久化机制RDB和AOF)
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
Redis的优势:
- 性能极高,Redis能读取的速度是 110000次/s,写的速度是81000次/s 。
- 丰富的数据类型,Redis支持二进制案例的Strings,lists,Hashes,Sets及Order Sets数据类型操作。
- 原子,Redis的所有操作都是原子性的,意思就是要么成功执行,要么失败完全不执行。单个操作是原子性的,多个操作也支持事务,即原子性。通过MULTI和EXEC指令包起来。
- 丰富的特性,Redis还支持publish/subscribe。通知,key过期等特性。
Redis与其他key-value存储有什么不同
- Redis有着更为复杂的数据结构并且提供对他们的原子性操作。这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
- Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
Redis的五种数据类型
基于key-value形式的数据字典,结构非常简单,没有数据表的概念,直接用键值对的形式完成数据的管理,Redis支持5中数据类型:
- 下载Redis:https://redis.io/download
- 解压,并在本地硬盘任意位置创建文件夹,在其中创建3个子文件夹
- bin:放置启动Redis的可执行文件
- db:放置数据文件
- etc:放置配置文件,设置Redis服务的端口、日志文件的位置、数据文件的位置等
启动Redis服务
- 进入redis目录,启动redis-server结合配置文件
sudo ./bin/redis-server ./etc/redis.conf
- 进入redis目录,启动redis-cli,启动redis客户端管理窗口,在此窗口中可以操作Redis数据库。
- 对数据进行操作
set name "Redis"
get name
- 关闭Redis服务
shutdown
- 退出客户端:control+c
Spring Boot整合Redis(CRUD)
Spring Data Redis操作Redis,步骤:
-
创建Maven工程
-
在pom.xml文件中引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mvc依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring Data Redis 启动依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--引入客户端,通过客户端操作redis-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 引入lombok简化实体类开发-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
- 创建实体类,实现序列化接口,否则无法存入Redis数据库
@Data
//实现序列化接口,才能够存入到Redis中,基于内存存储
public class Student implements Serializable{
private Integer id;
private String name;
private Double score;
private Date birthday;
}
-
启动Redis服务和启动Redis客户端
-
创建控制器Controller
@RestController
public class StudentHandleer{
//import org.springframework.data.redis.core.RedisTemplate
@Autowrited
pirvate RedisTemplate redisTemplate
/**
*添加学生(修改和添加类似,只需传入相同的key即可)
*/
@PostMapper("/set")
//@RequestBody把客户端传来的json转为java对象
public void set(@RequestBody Student student){
redisTemplate.opsForValue().set("student",student);
}
/**
*查询学生
*/
@GetMapping("/get/{key}")
public Student get(@PathVariable("key") String key){
return (Student)redisTemplate.opsForValue().get(key);
}
/**
*删除学生
*/
@DeleteMapping("/delete/{key}")
public boolean delete(@PathVariable("key")String key){
redisTemplate.delete(key);
return redisTemplate.hasKey(key);
}
}
- 创建application.yml配置文件(输入选spring.redis. database)
spring:
redis:
database:0
host: localhost
prot: 6379
- 创建启动类(Application.java)
@SpringBootApplication
public class Application{
public static void main(String args[]){
SpringApplication.run(Application.class,args);
}
}
- postMan测试接口,必须json格式
Redis存储时名字前面追加序列化字符,取出反序列化。(存序列化,取反序列化)
Redis五种数据类
- 字符串
@GetMapping("/String")
public String stringTest(){
redisTemplate.opsForValue().set("str","Hello word");
String str = redisTemplate.opsForValue().get("str");
return str;
}
- 列表(list,相当于管道,两边都可以加leftPush()左边加入,rightPush()右边加入)
lpush和rpop或rpush和lpop一起使用就是一个队列 lpush和lpop 或 rpush和rpop一起使用就是一个栈
@GetMapping("/list")
public List<String> listTest(){
ListOperations<String,String> listOperation= redisTemplate.opsForList()
listOperation.leftPush("list","hello") ;
listOperation.leftPush("list","World") ;
listOperation.leftPush("list","java") ;
List<String> list = listOperation.range("list",0,2);
return list;
}
//结果 ["java","World","hello"]
- 集合(set,无序不存在方向问题,数据value值是唯一的,重复只存一个)
sadd添加 scard key获取集合的成员数 smembers获取所有成员
@GetMapping("/set")
public Set<String> setTest(){
SetOperation<String,String> setOperation = redisTemplate.opsForSet();
setOperation.add("set","Hello");
setOperation.add("set","Hello");
setOperation.add("set","world");
setOperation.add("set","world");
setOperation.add("set","java");
setOperation.add("set","java");
Set<String> set = setOperation.members("set");
return set;
}
//结果 ["java","world","hello"]
- 有序集合(Zset)
zadd key num value zrange key start end
@GetMapping("/zset")
public Set<String> zsetTest(){
ZSetOperation<String,String> zsetOpartion = redisTemplate.opsForZSet();
zsetOpartion.add("zset","Hello",1); //1号
zsetOpartion.add("zset","World",2); //2号
zsetOpartion.add("zset","java",3); //3号
Set<String> set = zsetOpartion.range("zset",0,2);
return set;
}
//结果["Hello","World","java"]
- 哈希(哈希套哈希)
正常HashMap需要传入key-value两个参数
HashOperations key-hashkey-value三个参数 key是每一组数据的ID,hashkey和value是一组完整的HashMap数据,通过key来区分不同的HashMap。两key一value。key:HashMap(key:value)
HashMap hashMap1 = new HashMap();
hashMap1111.put(key1111,value1111);
HashMap hashMap2 = new HashMap();
hashMap2.put(key2,value2);
HashMap hashMap3 = new HashMap();
hashMap3.put(key3,value3);
HashOperations<String,String,String> hashOperations =redisTemplate.opsForHash();
hashOperations.put(hashMap1111,key1111,value1111);
hashOperations.put(hashMap2,key2,value2);
hashOperations.put(hashMap3,key3,value3);
@GetMapping("/hash")
public void hashTest(){
HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
hashOperations.put("key","hashkey","hashvalue");
System.out.println(hashOperations.get("key","hashkey"));
}
有序集合zset和hash存入无对应key不能重名。hash存的key会通过zset存入,所以存入的hash的key的值不能与zset中已有的key值重名。