上两篇文章从为什么用NoSQL,NoSQL分类简单概述,redis的基本情况(单线程),redis五大数据类型和三个特殊类型,还有一些简单的命令都说过了,这一片就是进阶版的,比如事务,主从复制等。下面一点点记录。
事务
Redis单条命令是保证原子性的,但是事务不保证原子性!
Redis事务本质:一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行。
Redis事务特性:一次性,序列性,排他性。
Redis没有隔离级别的概念。所有的命令在事务中并没有被执行,只有发起执行命令的时候才会执行。(执行命令exec)
Redis的事务:
- 开启事务
- 命令入队
- 执行事务
上面三步就是redis事务的主要三步,其中开始事务对应一个命令。命令入队就是正常的执行命令。执行事务也对应一个命令。下面演示一下。
-
使用事务一共就两个命令:
- 开始事务 multi
- 执行事务 exec
-
取消事务
- 取消事务 discard
这个很好理解的,如果事务开启了,一部分命令入队了,但是突然不想执行这些命令了,就可以取消了。
- 取消事务 discard
Redis为什么事务没有原子性:
这个其实要从错误原因开始。结合java来理解,错误分两种:
-
编译时异常(语法有错误,在redis中就是命令有错),这个时候事务中的所有命令都不会被执行。
-
运行时异常,如果事务队列中存在语法问题,那么执行命令的时候,其他命令是可以正常执行的,到了错误命令会抛出异常。
Redis监控Watch
redis本身是有锁的,其中分悲观锁和乐观锁。
- 悲观锁:很悲观。认为什么时候都会出问题,所以做什么都加锁。
-
乐观锁:很乐观。认为不会出什么问题,所以干什么都不加锁。更新数据的时候去判断一下在此期间与没有人修改过这个数据。大概的方式就是获取version,提交的时候判断version。version不一样会提交不了。
这里简单的展示一下watch的用法: watch name
这里注意是开始事务之后,执行事务之前改变的watch的对象的值。
而且最最重要的是!exec会自动解锁watch。比如上面的demo,如果继续开始事务,入队命令,另一个客户端改变这个值,但是还是可以执行成功的。
当然了,这个watch可以给某key加监视,但是也可以去掉监视。unwatch name。
Jedis
什么是Jedis?(Java+Redis = Jedis)
Jedis是Redis官方推荐的java连接开发工具。使用java操作Redis的中间件。下面是jedis的简单使用。
1.导入依赖。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
正常来讲只有这个依赖就可以了,但是我们在做项目的时候不得不使用各种工具包。主播这里还引入了fastjson。不过我现在比较喜欢用hutool。
2.查看源码。
特别喜欢这点,很多时候多看源码能让我们更加理解一些逻辑。导包成功红随便建个类,创建一个Jedis对象。然后点进去查看下Jedis源码就好。
其实这个也没必要瞎看,简单的看了下Jedis源码三千多行,光是构造方法就19个。不过很多不是很常用的我就跳过了。有几个常用的可以看一下各个参数都是什么。
其实这个是一个很有意思的过程。一层一层找上去可以更加清楚明了的知道一些事。jedis源码中有个继承父类的不需要参数的构造方法。下面我会把一层层的关系展示出来。特别有意思的东西。
其实看源码,一层层分析剥开,是件很有意思的事。继续往下说了。我先创建一个无参的jedis,因为我是本地环境,localhost和6379就可以满足了。然后可以用Jedis.看一下,其实所有的redis命令jedis都有的,简单的写点测试代码:
我也是写完了才发现第三个输出语句写错了。当时脑子一抽当成输出值用//分割了。不过因为没有这个key所以报null这个就当个测试也没啥问题。简单来说,redis所有的命令都可以用jedis来实现。感兴趣的可以自己去看看。因为太多了,而且上一篇文章说的很详细了,所以我也不重新说了。
当然了如果不确定的话,也可以用jedis ping一下,返回pong说明连接成功了。
其实真的,Jedis中的方法。和redis命令百分之九十九都是一样的(之所以不敢说百分百是怕jedis版本没跟上)。所以jedis就说到这,就是为了知道有这么个东西,并且在不适用spring boot封装好的redisTemplate也可以使用就行了。
Spring boot整合Redis
毕竟现在spring boot是项目的基石,所以还是要说怎么整合的。
Spring Data其实是和spring boot齐名的一个项目。如下面目录。只不过spring boot是一个项目基石。而data一般都是继承的其他技术。
下面创建一个spring boot项目(我个人习惯官网创建。地址如下:https://start.spring.io/)
在spring boot 2以上,原来使用的jedis被替换成了lettuce
Jedis:jedis底层采用的是直连。多个线程操作的话,是不安全的。如果想要避免不安全,要使用jedis pool(连接池)。更像是bio模式
Lettuce:底层采用netty。实例可以在多个线程中进行共享。不存在线程不安全的情况。可以减少线程数量了,这个更像是nio模式。
继续说,说一个spring boot的知识:所有的配置都有一个自动配置类。(redis是RedisAutoConfiguration)。而自动配置类都会绑定一个properties配置文件。
源码分析
(上面的注解有点说的不准确。是如果这个类不存在,则生效。)
下面是源码中的两个bean:
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
- 首先,由于string类型是最常用的类型,所以单独写了一个bean。
- 其次,默认的redistemplate没有过多的设置,redis对象都是需要序列化的
redistemplate的两个类型都是Object。我们使用后需要强制转换成string,object - 最主要的是这个没有类才生效的注解,使得我们可以自己定义redisTemplate。
在代码中使用:配置文件注意2.x以上版本一定要使用lettuce,因为jedis虽然可以选择(有提示),但是实际上其实现类中好多类都不存在。根本是不生效的。
简单的导包,配置完host和端口,其实就可以在项目中测试了:
配置文件(只写了这两行)
spring.redis.host = 127.0.0.1
spring.redis.port = 6379
测试代码如下。
@SpringBootTest
class SpringRedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("key1", "value1");
System.out.println(redisTemplate.opsForValue().get("key2"));
System.out.println(redisTemplate.opsForValue().get("key1"));
}
}
反正我是正常执行了,并且给出的结果也是想要的。
这一块是想到哪讲到哪,也没啥顺序,上面说了存入redis 的一定要序列化。而序列化的过程是在redisTemplate中的(stringRedisTemplate继承自redisTemplate)。可以去看redisTemplate的源码:
所以有可能会出现中文乱码的情况。如果想要解决这个问题,肯定是要自己定义RedisTemplate类(别忘了当时给定类是如果存在则不生效的哟)
还有就是存到redis本身的是要序列化的,而Object,Object本身是没有序列化的,如下代码:
当然了,上面demo的前提是这个Test1类是没有序列化的。如果这个类序列化了也是ok的。继续说这个RedisTemplate模板可以自己去实现,一般会自己去选择序列化方式,这个可以配置的。如下选择:
其实这块up主讲了很多东西,但是和stringRedisTemplate功能差不多。怎么说呢,很多东西学习很多真的有用么?当你有了特殊需求,确实需要特殊处理。但是当你基本使用,然后你再配一个模板,说真的,我都觉得你是在浪费时间。今天喝了点酒所以想多说几句。关于知识这一块,我一向觉得够用就行。我经历过新开创的项目领导就非要用mycat分库分表的。也见过面试中es,redis,消息队列都问了然后他们公司项目还在用ssm的。今天在做需求的时候还做了一个简单的数值转化成大写数字金额的功能。结果百度一搜索,千篇一律的狗屁代码。一百多行,从判断是不是数字类型到去除逗号,甚至有的千百万兆单位都有。我就呵呵了,多少人多少业务连上百万的金额都没有啊,还几把千百万兆,这辈子是用不着了吧?而且这种狗屁代码还转载多次,百度搜索前三页差不多点开都是这玩意,有屁用?知识技术这种东西,不针对事实情况就踏马是耍流氓而已。
当然了,这个up主讲了深一层的自己封装确实挺好的,扩展扩展眼界。其实实现的方法也比较简单,自己写redisTemplate。然后自己去做一些配置,但是具体配置什么根据实际情况一个个参数去挑吧,我就不再写一个stringRedisTemplate和大家分享了。这块跳过。
下一个模块是up主给大家封装了一些redisTemplate的工具类,就是一个把ops...set/get...之类的命令封装成一个RedisUtil类来操作。其实这个我觉得没有什么学的必要。毕竟明白底层的实现,然后熟悉公司封装好的命令就行了。毕竟我经历过三家公司,每一个公司是有自己的工具包的。比如现在的习惯用XXXutils命令,但是第一家喜欢用XXXtool命名。几乎很少公司去适应你,就得你去适应公司的。
小结:其实这个redis的使用,尤其是java使用redis是很简单的,毕竟大语种几乎前人几乎已经造好了轮子。但是我们更重要的是去理解redis的思想和每一种数据结构的用处和使用场景。而且对于程序员来说,思路永远大于技术。
Redis的conf配置文件
其实配置文件是很重要的东西,很多看基本或重要的配置都是在配置文件中,要学会看懂配置文件。
1. redis的配置文件中,对单位的大小写不敏感。(1Gb 1gb 1gB都可以)
2. redis的配置文件中可以引入(包含)别的文件。
3. 网络上。
bind 127.0.0.1(绑定的ip)
protected-mode yes(保护模式)
port 6379(端口设置)
tcp-backlog 511(这个稍微复杂一点。其实可以理解为tcp三次握手,第一次简单理解成客户端打招呼(未读消息)。 当服务端收到招呼再回复消息(已读已回)后,如果再发来消息就是聊天消息了。而这个同时聊天消息的最大数就是上面设置的,但是这个值也不仅仅是上面这个tcp-backlog 决定的。由somaxconn和tcp_max_syn_backlog 两个值来达到扩大的效果的。附上一张图)
timeout 0 (设置客户端连接时的超时时间,单位为秒。当客户端在这段时间!内没有发出任何指令,那么关闭该连接默认值:0代表禁用,永不关闭。注意这个不是说0秒超时)
tcp-keepalive 0 (心跳间隔,单位是秒。要关闭这个连接需要两倍的这个时间值。这里是0就是不用发吧,我看网上说 从redis3.2.1开始默认值为300秒)
daemonize no(是否将redis作为守护线程(后台也不停止)no是不,yes是是)
pidfile /var/run/redis_6379.pid (如果是后台线程,则需要指定一个pid文件)
4. 通用
loglevel notice (日志级别,直接看图吧)
logfile "" (日志打印出来肯定要在一个文件里。这个就是输出的文件名)
databases 16 (数据库的数量,默认16个说过了的。)
5. 快照(这个是做持久化用到的)
持久化:在规定的时间内执行了多少次操作,则会持久化到文件,rdb.aof
redis是个内存数据库,如果没有持久化,那么断电即失。所有有时候我们也要做持久化操作。
save 900 1 (如果900秒内,至少一个key进行了修改,那我们进行持久化操作)
save 300 10 (如果300秒内,至少10个key进行了修改,那么我们后进行持久化操作)
save 60 10000(如果60秒内,至少10000个key进行了修改,那么我们后进行持久化操作)
其实这个这是简单罗列了三种数据修改级别的情况,我们在真正使用中大多数会自定义这个配置数据!
stop-writes-on-bgsave-error yes (如果持久化出错了是不是还要继续工作。默认yes)
rdbcompression yes(是否压缩rdb文件,默认是压缩的)
rdbchecksum yes (保存rdb文件的时候是不是进行错误的检查校验)
dbfilename dump.rdb (设置快照的名称,也就是rdb文件的名称)
dir ./ (rdb文件保存的目录)
6. 复制 (这块主从复制的后面讲,现在先不整理了)
7.安全SECURITY
这里一定要说到redis的密码了。默认的话redis 是没有密码的,可以在客户端获取一下:
如图所示是没有的。可以在配置文件中配置。如下位置(配置文件中配置密码后启动要指定配置文件):
也可以用控制台设置(这种每次启动都要去设置,关闭重启就没了):
config set requirepass "8023520"
maxclients 10000(redis客户端最大数量)
maxmemory <bytes>(redis配置的最大的内存容量)
maxmemory-policy noeviction(内存到达上限的时候的处理策略)这里有几种机制:
noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键
allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键
volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键
allkeys-random:加入键的时候如果过限,从所有key随机删除
volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐
volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键
volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
allkeys-lfu:从所有键中驱逐使用频率最少的键
8.append only模式 aof配置
appendonly no(默认不开启aof模式,默认是使用rdb方式持久化的。在大部分情况下,rdb就已经足够使用了。)
appendfilename "appendonly.aof"(aof的持久化的文件名字)
appendfsync everysec(每秒执行一次同步。可以设置成always,是每次修改都同步。这个很消耗性能。还可以设置成no,不执行同步)
具体的配置下一章讲解吧。这一篇笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注。也祝大家工作顺顺利利!只要学不死,就要往死学。与君共勉!