NoSQL四大分类
1、K-V存储数据库(key-value)
特点:简单,易部署
缺点:对于部分值修改需要遍历操作,效率低下。
产品:redis、ssdb
2、列存储数据库
特点:键仍然存在,他们的特点是指向多个列,这些列由列族安排。
如:hbase
3、文档型数据库
以json的形式存储,可以看出key-value的升级版
如MongoDB
4.图形数据库
二进制数据的存储
如:infoGriid
Redis概念
1、基于内存数据存储被作为数据库缓存消息中间件
2、所有的数据保存在内存中,读写快,但断电会消失。
3、redis具有持久化机制,会定期的将数据chii’uhua
Redis特点
1、高性能的key value数据库。
2、支持丰富的数据类型(String,set,list)
3、redis支持持久化
4、redis单线程、单进程,效率高,redis分布式锁。
redis启动
1、redis-server启动:使用的是redis-server脚本中的默认配置
2、指定配置文件启动
-进入原码复制redis.conf
-修改配置
-加载配置启动
./redis-server ../redis.conf
redis中的库
a.redis默认有一些库,库的编号从0号开始,默认使用0号库。
b.切换库
select 1 // 数字表示库的编号
#每个库都是独立的,互不影响
c.清空库
FLUSHDB 0 库号
FLUSHALL 清空所有库
redis指令
key操作
1.set
set key value
2.exists 是否存在key 存在1 不存在 0
3.del 删除key
可以删除一个或多个
del key
del key1 key2
4.keys 匹配key
keys * 匹配所有
keys h* 匹配以h开头的多个字符
keys h? 匹配两个字符,且以h开头
keys h[ae] 匹配a,e中的一个
keys h[ae][ae] 匹配第二个字母a,e和第三个字母为a,e
5.expire
设置过期时间
expire key seconds
6.move
移动
move key 库号
7.PEXPIRE key 设置时间 毫秒 PERSIST 设置永久有效。
8.TTL 查看key过期时间
返回 -1 永久 -2 不存在
9.PTL 查看key时间 返回毫秒
返回 -1 永久 -2 不存在
10.randomkey 随机返回库中的一个key
11.RENAME
rename key 重命名key
12type
type key key的类型 不存在返回null
类型操作
1、String
set key 定义key
get key 获取可以值
mset key1,key2,key3 设置多个值
mget key1,key2,key3 获取多个值
getset 获取原来的值,并赋值新的值
strlen 获取值的长度
append 追加值 append key 追加值
getrange start end end为-1表示末尾
setex key value seconds 开始就设置时间
pssetex key value seconds 设置毫秒时间
setnx key value
判断键是否存在,不存在添加,存在不做任何处理
msetnx key value key value 键有一个存在不执行操作,一个都不存在执行操作。
decr key 减一操作
decrby key 值 指定每次减多少
incr key 每次增加1
incrby key 指定值 每次增加指定值
incrbyfloat 增加浮点值
2.list
有顺序且可以重复
rpush list value value
LPUSH list zhangsan liyong xiaoming
命令 list名 多个值
遍历列表
lrange list 0 -1
lpushx 只能往已经存在的list中添加值
rpushx
lpoop 返回并移除左边的元素
rpoop
llen 查看list中的个数
lset key index newvalue
lindex 根据指定下标获取一个值
lrem key 删除个数 移除重复元素
ltirm 保留指定区间的元素
linsert 插入
linsert list before/after key value
3.set
元素无序且不可重复
sadd key value value
smembers key
scard 返回元素集合
spop 移除一个 可以指定移除个数
smove 从一个集合向另一个集合移动元素,必须是同一种集合
smove 源 目标 值
srem key value value 删除多个
srandmember 随机返回一个值
sdiff set1 set2 去除set1包含set2中的值
sinter set1 set2 set3 求交集
sunion set1 set2 求并集
4.zset
可排序的set集合,无序,排除不可重复
zadd key 分数 value 分数 value
zcard 返回个数
zrange key 0 -1 遍历
zrange key 0 -1 withscores 带分数
zrangebyscore
zrank key xiaoming 排名
zscore key value 显示某个元素的分数
zrem key value value 删除多个元素
zincrby 给指定的元素加分
5.harsh
map结构,存在key value 无序
hset key harshkey value 创建map集合
hget key harshkey
hgetall 遍历键值遍历
hdel key harshkey
hexists key harshkey
hkeys key 遍历所有的键
hvalues key 遍历所有
redis持久化
保存的是当前时刻的数据,重启加载快照。
1、快照snapshot,redis默认开启的持久化方式。快照文件以rdb结尾,也叫rdb方式。
-客户端使用BGSAVE或SAVE指令,生成快照。bgsave由fork(创建进程的函数)创建一个子进程,父进程继续处理命令,不会阻塞redis服务。刚开始父进程与子进程共享相同的内存,知道父进程或子进程开始写操作,共享内存结束。能够加速快照的创建。而save命令在快照创建完成之前,不处理任何命令,会阻塞服务。
-服务器配置自动触发
#15分钟内有一个字段变化创建快照
#5分钟有十个字段发生变化创建快照
#1分钟有一个字段触发创建快照
save 900 1
save 300 10
save 60 100
-客户端发起关闭命令时会做一次快照,执行的save命令。
-配置快照名称和位置
2、AOF append only file
将所有redis写命令记录到日志文件中,redis只需要重头到尾执行AOF中的命令就可以恢复数据。
开启AOF
appenonly yes
appendfilename "appendonly.aof"
日志追加频率
- always 需要进行大量的写操作,不推荐使用。
- everysec 每一秒同步一次。
- no 由操作系统决定什么时候同步。
appensync erysec
3.AOF重写
压缩AOF文件,以防每次AOF重头执行,做多余的操作。
BGREWRITEAOF 重写AOF
自动重写配置
auto-aof-rewrite-percentage 100 体积到达1倍时重写
auto-aof-rewrite-min-size 64mb 执行AOF重写时,文件的最小体积,默认值为64MB,超过则大于一倍重写。
4.重写原理
- redis调用fork,现有父子两个进程子进程根据内存中的数据快照,往临时文件中写入重建数据库状态命令。
- 父进程继续处理client请求,除了把命令写入到原来的AOF中。同时把收到的写命令缓存起来,保证子进程重写失败不出现问题。
- 3当子进程把快照内容以命令方式写入临时文件中后,子进程发信号通知父进程,然后父进程把缓存的写命令也写入到到临时文件。
- 现在父进程可以使用临时文件替换老的AOF文件,并重命名,后面收到的写命令也开始往新的AOF中追加。
java操作redis
redis默认不开启远程连接,在配置中修改
bind 0.0.0.0
依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
helloworld
public static void main(String[] args) {
// 创建对象
Jedis jedis = new Jedis("172.18.0.130 ",6379);
// 选择库
jedis.select(0);
// 获取所有的key信息
Set<String> keys = jedis.keys("*");
keys.forEach(key -> System.out.println("key:" + key) );
jedis.close();
}
注解:所有的操作都写在jdis中可以查看类,获取具体操作方法,与命命令行操作一致。
springboot整合redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
1.redisTemplate
2.StringRedisTemplate(redisTemplate的一个子类)
区别:redisTemplate<string,object>,StringRedisTemplate<String,String>redisTemplate存放对象redis自动序列化与反序列化
注意:序列化的对象必须实现序列化接口
@Autowired
RedisTemplate redisTemplate;
@Test
void contextLoads() {
// key操作
redisTemplate.opsForValue();
// list
redisTemplate.opsForList();
// harsh
redisTemplate.opsForHash();
// set
redisTemplate.opsForSet();
}
注意:StringRedisTemplate操作不需要序列化随意操作,但是redisTemplate操作时因为对象会序列化因此需要注意此问题。默认使用的是jddk序列化。
// 获取不到值,因为name是没有序列化的,而redisTemplate是序列化后去取值,所以取不到
redisTemplate.opsForValue().get("name");
// 保存时,key也会被序列化,结果如下图
redisTemplate.opsForValue().set("key",new User("liyong",23));
因此需要指定序列化方式,一边key值保持字符串原状。
// 指定key的序列化方式
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.opsForValue().set("key",new User("liyong",23));
同时如果是harsh还需要修改harsh的key,否则也会被序列化。
// 指定key的序列化方式
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.opsForHash().put("harsh","key",new User("liyong",23));
3.spring data为简化我们的操作同时提供了bound API,可以对key进行多个操作的绑定,从而简化对同一个key的多个操作。
// 对同一个key 需要进行多种操作。
redisTemplate.opsForValue().set("key","value");
redisTemplate.opsForSet().add("key","value");
redisTemplate.opsForList().leftPush("key","value");
// 使用绑定简化操作
BoundValueOperations<String,String> boundValueOperations = redisTemplate.boundValueOps("key");
boundValueOperations.set("value");
boundValueOperations.append("value");
boundValueOperations.get();
注解:同样可以对list,harsh,set进行绑定
redis应用
1.场景
- 收机验证码(超时特性)
- 具有时效性的功能(取消订单)
- 分布式集群Session共享
- zset排行榜
- 分布式缓存
- 存放认证后端token信息
- 集群分布式锁
- redis LRA脚本实现分布式锁
2、案例 分布式缓存
a.前置知识 - 概念;计算机内存中的一段数据
- 特点:读写快,断电丢失。
- 核心解决问题:可以减轻数据库的访问压力
- 适用于极少发生修改的数据
- 本地缓存:存在应用服务器内存中的数据为本地缓存
- 分布式缓存:存储在当前应用服务器之外
b.利用mybatis源码实现RedisCache - 分析源码得知mybaits的缓存继承了cache重写了实现,因此换成自己的redis实现即可。
public class RedisCache implements Cache {
// 当前缓存的namespace
private final String id;
public RedisCache(String id) {
this.id = id;
}
// 如不返回会报name错误
@Override
public String getId() {
return this.id;
}
@Override
public void putObject(Object key, Object value) {
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextHand.getBean(RedisTemplate.class,"redisTemplate");
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.opsForHash().put(id.toString(),key.toString(),value);
}
@Override
public Object getObject(Object key) {
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextHand.getBean(RedisTemplate.class,"redisTemplate");
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate.opsForHash().get(id.toString(),key.toString());
}
// 增删改时清空缓存,mybatis没有实现
@Override
public Object removeObject(Object key) {
return null;
}
// 增删改时清空缓存,mybatis默认方法
@Override
public void clear() {
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextHand.getBean(RedisTemplate.class,"redisTemplate");
redisTemplate.delete(id.toString());
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
}