初始Redis认识NoSQL
非关系数据库
对比SQL
- 结构
- 关系
SQL中表和表之间可能会有一定的关系,NoSQL中的每个数据都没有关联
- 查询
没有固定的语法可以查询NoSQL中的句子,每个不同的库都有不同的语法
- 事务
SQL有ACID事务;但是NoSQL可能没有事务,即使有事务,也只能满足事务的基本一致性
了解RedisRedis诞生于2009年,是一个基于内存键值的NoSQL数据库
特征:
- value支持多种不同的数据结构,具有丰富的功能
- 每个命令都有原子性
- 延迟低,速度快(基于内存,IO多路复用,编码好)
- 支持数据的持久性
- 支持主从集群、分片集群
// 对MSET添加键值 [k1 v1 k2 v2]// 检查所有符合模板的KEY,不建议在生产环境设备上使用KEYS [pattern]// 删除选定的key,删除多个DEL [key...]// 检查对应键是否存在EXISTS [key]// 为key设置有效期,有效期届时,key将自动删除EXPIREEEE [key seconds]// 查看key有多少有效期TTL [key]
不同数据结构的操作命令- String
- string:普通字符串
- int:整数类型可以自增自减操作
- float:浮点类型可以自增自减操作
SET:添加或修改现有String类型的键值:根据key获得String类型的valueMSET:批量添加多个String类型的键值对MGET:多个String类型的valueINCRR批量获取:让一个完整的key自增1INCRBY:让整形key自增指定步长,列如:incrby num 2 NUM值自增2INCRBYFLOAT:增加一个浮点类型的数字并指定步长SETNX:添加String类型的键值对,前提是key不存在,如果存在,则不执行SETEX:添加String类型的键值对,并指定有效期
key的结构
- Hash类型
HSET key field value:添加或修改hash类型的field值HGET key field:获得hash类型key的field值HDEL key field:删除指定hash类型的field字段HMSET:批量添加多个hash类型key的field值HMGET:获得多个hash类型key的field值HGETALLL:在hash类型的key中获得所有的field和valueHKEYS:在hash类型的key中获得所有fieldHVALS:在hash类型的key中获得所有valueHINCRBY:让hash类型key的字段值自增并指定步长HSETNX:添加hash类型keyfield值,前提是这个field不存在,否则不执行
- List类型
LPUSH key element..:在列表左侧插入一个或多个元素LPOP key:删除并返回列表左侧的第一个元素,而不返回nilRPUSH key element..:在链表右侧插入一个或多个元素RPOP key:清除并返回列表右侧的第一个元素,nillllllangenge没有返回 key star ned:BLPOP和返回角标范围内的所有元素(包括左和右)BRPOP:类似于LPOP和RPOP,只是没有元素等待指定时间,而不是直接返回nil/honcode>
- Set
// SADDD单个set操作 key member..:SREMM向set添加一个或多个元素 key member..:SCARD在set中移除指定元素 key:SISMEMBER返回set中元素的数量 key member:判断SMEMERS在SET中是否存在一个元素 key:获取set中的所有元素/// SINTER多个set操作 key1 key2..:SDIFFF1与key2的交集 key1 key2..:SUNIONNION key1 key2..:并集key1和key2
- SortedSet
ZADD key score member:在sorted中添加一个或多个 set,如果存在,则更新score值ZREM key member:删除sorted ZSCOREE是set中的指定元素 key member:获取sorted set中指定元素的score值ZRANK key member:获取sorted ZCARD在set中指定元素的排名 key:获取sorted ZCOUNTset中的元素数 key min max:ZINCRBY统计score值在给定范围内的所有元素 key increment member:让sorted set中的指定元素自增,指定的increment值ZRANGE key min max:根据score排序后,获得指定排名范围内的元素ZRANGERBYSCORE key min max:按照score排序后,在指定的score范围内获取元素ZDIFF、ZINTER、ZUNION:求差集、交集、并集注意:所有排名默认为升序。如果要降序,可以在命令Z后面加REV。
Java客户端Jedis客户端Jedis基本用法- 创建一个maven项目,pom.xml导入依赖
<dependencies> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>4.3.1</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency> </dependencies>
- 创建测试类
- 建立连接
@Resource private Jedis jedis; @BeforeEach public void init(){ jedis = new Jedis("127.0.0.1",6379); // jedis.auth(password); 有密码认证密码 // 选择库 jedis.select(0); }
- 测试String类型
@Test public void testString(){ jedis.set("name","希诚"); System.out.println(jedis.get("name")); }
- 测试Hash类
@Test public void testHash(){ jedis.hset("nameSet","name","希诚"); jedis.hset("nameSet","age","20"); Map<String, String> nameSet = jedis.hgetAll("nameSet"); System.out.println(nameSet); }
- 最后,不要忘记关闭连接
@AfterEach public void close(){ if (jedis != null) { jedis.close(); } }
Jedis连接池创建JedisconectionFactory
package com.xc.jedis.util;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;import java.time.Duration;import java.time.temporal.ChronoUnit;import java.time.temporal.TemporalUnit;/** * @author xc * @date 2023/4/9 10:53 */public class JedisConnectionFactory { private final static JedisPool jedisPool; static { // 配置连接池 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); // 设置最大连接数 jedisPoolConfig.setMaxTotal(8); // 设置最大的空闲连接 jedisPoolConfig.setMaxIdle(8); // 设置最小空闲连接 jedisPoolConfig.setMinIdle(0); // 设置等待时间,在没有连接的情况下,等待多少时间直到等待空闲连接,否则会报告错误 jedisPoolConfig.setMaxWait(Duration.of(1000, ChronoUnit.MILLENNIA)); // 创建连接对象 jedisPool = new JedisPool(jedisPoolConfig,"127.0.0.1",6379,1000); } public static Jedis getJedis() { return jedisPool.getResource(); }}
在测试类中进行测试
@Test public void testJedisPool(){ Jedis jedisByPool = JedisConnectionFactory.getJedis(); jedisByPool.set("xcxc","666"); System.out.println(jedisByPool.get("xcxc")); }
SpringDatardis客户端基本操作- 创建springboot项目,引入依赖性
<!-- 依赖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.在yml文件中配置我们需要的redis和连接池的信息
spring: redis: host: localhost port: 6379 password: lettuce: pool: max-active: 8 #最大连接 max-idle: 8 #最大的空闲连接 min-idle: 0 #最小空间连接 max-wait: 100 #等待时间最长
- 编写测试类
@Resource private RedisTemplate redisTemplate; @Test void contextLoads() { redisTemplate.opsForValue().set("name","希诚"); System.out.println(redisTemplate.opsForValue().get("name")); }
以序列化的形式存储
SpringDateredis的序列化方法缺点:
- 可读性差
- 内存占用较大
怎么解决:
- redis配置类
package com.xc.springdateredisdemo.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.GenericJacksonJsonRedisSerializer;import org.springframework.data.redis.serializer.RedisSerializer;import org.springframework.stereotype.Component;/** * @author xc * @date 2023/4/9 11:45 */@Configurationpublic class RedisConfig { @Bean public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { // 创建redis对象 RedisTemplate<String,Object> template = new RedisTemplate<>(); // 设置连接工厂 template.setConnectionFactory(redisConnectionFactory); // 创建JSON序列化工具 GenericJacksonJsonRedisSerializer jackson2JsonRedisSerializer = new GenericJacksonJsonRedisSerializer(); // 设置Key的序列化 template.setKeySerializer(RedisSerializer.string()); template.setHashKeySerializer(RedisSerializer.string()); // Value序列化设置 template.setValueSerializer(jackson2JsonRedisSerializer); template.setHashValueSerializer(jackson2JsonRedisSerializer); return template; }}
- 测试
@Resource private RedisTemplate<String,Object> redisTemplate; @Test void contextLoads() { redisTemplate.opsForValue().set("name","希诚"); System.out.println(redisTemplate.opsForValue().get("name")); }
发现没有序列化
随便创建一个对象类再测试
user对象
@Datapublic class User{ private String name; private int age; public User(){} public User(String name, int age) { this.name = name; this.age = age; }}
测试
@Test void testUser() { redisTemplate.opsForValue().set("user:100",new User(“希诚”,20)); System.out.println(redisTemplate.opsForValue().get("user:100")); }
你会发现每次都有一个@class,占用内存
使用stringredistemplatetet
@Resource private StringRedisTemplate stringRedisTemplate; @Test void testString() { stringRedisTemplate.opsForValue().set("gender","男"); System.out.println(stringRedisTemplate.opsForValue().get("gender")); } @Test void testUser() { User user = new User(“希诚66”20); // 每次都需要手动序列化和反序列化(使用熟悉的序列化工具) Gson gson = new Gson(); String json = gson.toJson(user); stringRedisTemplate.opsForValue().set("user:200",json); String s = stringRedisTemplate.opsForValue().get("user:200"); User user1 = gson.fromJson(s, User.class); System.out.println(user1); }
结果