实现一个项目,无论项目多复杂,核心的功能就是增删改查。可以使用的到技术,比如 Java 基础语法,jsp,servlet,html,jdbc…………可以实现其基础功能。项目随着需求的变化,而不断升级,此时强调的是可扩展能力,如果使用普通实现功能的技术比较麻烦,那么衍生出的就是 Spring,SpringMVC,MyBatis 等框架技术来解决扩展性问题。当项目功能完成且具备扩展能力,此时就会产生性能问题,随着解决此类问题的技术就是:NoSql、java 线程、Nginx…………
1、NoSql 使用的两个场景
2、NoSql 数据库概述
3、redis 安装
4、五大数据类型
5、配置文件
6、订阅与发布
7、redis 6 之后的新类型
8、jedis
9、springboot 整合 redis
10、事务和锁机制
11、事务冲突
12、持久化
13、主从复制
14、集群
15、redis 应用问题
cd /opt
yum install gcc
tar -zxvf + 安装包的名字
make
redis-cli
keys *
查询当前数据库(Redis 有很多数据库,默认的数据库的其 0 号库)的所有 key 值,未插入数据时为空set key value
设置键值对,向数据库插入数据后,再次使用 keys *
指令查询数据库中的key
值exists + (key名字)
,查询当前 key 是否在数据库中,返回 1 在,返回 0 不在type + (key名字)
,查询当前 key 的数据类型,可以看到刚刚定义的 key 是 string 类型del + key 名
删除此 keyunlink + key名
根据 value 选择非阻塞删除,使用此指令不是真正的删除此 key ,真正删除操作需要在后续的异步操作expire + key名
设置 key 值的过期时间,通过 ttl + key 名检测当前 key 值多少秒过期,-1 表示永不过期,-2 表示已过期select + 数据库号
表示切换数据库,下面就是切换数据库为 1 号数据库dbsize
查询当前数据库的 key 的数量Redis 字符串(String)是 Redis 中基本数据类型,一个 key 对应一个 value,String 类型是
二进制安全
的。意味 redis 的 string 可以包含任意数据,比如 jpg 图片或者序列化的对象。一个 Redis 中字符串 value 最多512 M
Redis 中的 List 采用的是 quickList (快速链表),一开始在列表中的数据比较少的时候,会使用一块连续的内存空间,这个结构是 zipList(压缩链表),它将所有的元素紧挨在一起进行放置,分配的是一块连续的空间,当数据量较多的时候才会改成 quickList 因为普通的链表需要附加的指针空间太大,会比较浪费空间。Redis 将链表和 zipList 结合起来组成了 quickList 也就是多个 zipList 使用双指针串联起来,既满足了插入删除的高效,也节省了空间
Set 中提供了可以判断值是否在 set 中的接口,这是 List 中没有的,Set 是一个无序不重复集合,其底层是一个 value 为 null 的 hash 表,所以添加删除查找的时间复杂度都是 O(1)
Redis 的 set 机构和 Java 的 set 结构类似,内部使用的也是 hash 结构,所有的 value 值都是指向同一个内部值
Hash 是一个键值对集合,Redis 的 Hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合存储对象,就像 Java 的 map 一样
基本指令:
Hash 的数据结构:
有两种,zipList,hashtable,当 field - value 长度比较短个数较少时,使用 zipList,否则使用 hashtable
Zset 和 set 的区别不大,也是一个包含不重复元素的集合,不同之处就是每个成员添加了一个 score 属性,这个评分被用来按从最高或者最低进行排序,集合的成员是唯一的,评分不是唯一的
bitemap 和 set 集合比较:
- 在实际业务中常用统计方面的需求,并且有时还需要统计不重复元素的个数(基数问题),在 MySQL 表中,使用 distinct count 计算不重复个数
- 在 Redis 中可以使用 hash set bitmap 来进行统计,但是随着数据量增加,这三种方式占用空间会越来越大,对于非常大的数据集是不可行的。所以考虑降低一定的精度来进行存储,Redis 退出 HyperLogLog。
- HyperLogLog 只需要花费 12 kb 的大小就能存储 2 ^ 64 个不同的基数(不重复的数),相对节省了很大的空间
提供经纬设置,查询,范围查询,距离查询,经纬度 Hash 等常见操作
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
public static void main(String[] args) {
JedisShardInfo shardInfo = new JedisShardInfo("redis:///*使用你云服务器的 ip 地址*/:6379");
shardInfo.setPassword("/*使用你redis的的密码*/");
//创建 jedis 类
Jedis jedis = new Jedis(shardInfo);
//测试
String value = jedis.ping();
System.out.println(value);
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
#Redis本地服务器地址,注意要开启redis服务,即那个redis-server.exe
spring.redis.host=你redis的地址 我的是云服务器的地址
#Redis服务器端口,默认为6379.若有改动按改动后的来
spring.redis.port=6379
#Redis服务器连接密码,默认为空,若有设置按设置的来
spring.redis.password=
#连接池最大连接数,若为负责则表示没有任何限制
spring.redis.jedis.pool.max-active=20
#连接池最大阻塞等待时间,若为负责则表示没有任何限制
spring.redis.jedis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=5
#连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
package com.example.demo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-10-12
* Time: 9:43
*/
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
package com.example.demo.controller;
import com.example.demo.config.RedisConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-10-12
* Time: 9:50
*/
@RestController
@RequestMapping("/testRedis")
public class RedisController {
@Autowired
private RedisTemplate redisTemplate;
@RequestMapping("/redis")
public String testRedis(){
redisTemplate.opsForValue().set("name","lucy");
String name = (String)redisTemplate.opsForValue().get("name");
return name;
}
}
Redis 的事务和 MySql 的完全不一样
Redis 中的事务:是一个单独的隔离操作,事务中所有的指令都会序列化,按顺序执行,在事务执行过程中,其他客户端的指令不会打断指令。
Redis 事务的主要作用就是为了串联多个命令,防止其他命令插队
三个指令:Multi、Exec、Discard
事物的错误处理:
事物冲突:三个人同时操作一个账户的金额,同时查询都是有 10 ¥,用户 1 取 8 ¥,用户 2 取 4 ¥,用户 3 去 2 ¥,按说每个用户看到都是 10 ¥ 如果取钱操作应该成功,但是这样就会使账户成负数了,这显然是不合理的,随着用户取走钱,对应其他用户所取钱的范围就应该减少
解决方法:
unwatch 指令清除对 key 的监视
Redis 事务的三个特性