6.4、通过jedis再次理解事务
package com.howie.jedis; import com.alibaba.fastjson.JSONObject; import redis.clients.jedis.Jedis; import redis.clients.jedis.Transaction; public class JedisTest { public static void main(String[] args) { // 主机号 + 端口号 Jedis jedis = new Jedis("127.0.0.1",6379); // 连接远程Redis服务 JSONObject data = new JSONObject(); data.put("hello","world"); data.put("name","howie"); // 1、开启事务 Transaction multi = jedis.multi(); try { multi.set("k1","v1"); // 2、命令入队 multi.set("json_data",data.toString()); // 2、命令入队 // 模拟异常 int sum = 1/0; // 3、执行事务 multi.exec(); System.out.println(jedis.get("k1")); System.out.println(jedis.get("json_data")); } catch (Exception e) { multi.discard(); // 放弃事务 e.printStackTrace(); } finally { // 关闭连接 jedis.close(); } } }
7、SpringBoot整合Redis
SpringBoot操作数据: spring-data jpa jdbc mongodb redis !
SpringData也是和SpringBoot齐名的项目!
7.1、Redis整合SpringBoot
说明:在SpringBoot 2.x 之后,原来使用的jedis被替换成了lettuce。
jedis:采用的直连,多个线程操作的话,是不安全的。如果想要避免不安全因素,就要使用jedis pool连接池。更像 BIO 模式
lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了。更像NIO模式
1、新建SpringBoot项目
源码分析(RedisAutoConfiguration.java):
@Bean @ConditionalOnMissingBean(name = "redisTemplate") // 此注解功能,如果没有名为 "redisTemplate" 的类注入Bean容器,就使用以下的默认的,言外之意,我们要自定义一个 "redisTemplate" public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { // 默认的 RedisTemplate 是没有过多的配置,Redis对象都需要序列化! // 两个泛型都是 Object 类型,我们后面使用需要强制转换 <String,Object> RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean // 由于String类型是我们Redis中最常用的类型,所以单独提出来了一个Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; }
2、导入依赖(创建SpringBoot时,勾选对应内容即可)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
3、修改配置文件,配置Redis连接
# 配置Redis连接,这只是基本配置,当然在实际开发中,可根据需要配置更多的redis服务 spring: redis: host: 127.0.0.1 port: 6379
4、测试!注意本地Redis服务要打开才能测试成功!
class Day10ApplicationTests { @Autowired private RedisTemplate<String,String> template; @Test void contextLoads() { /* RedisTemplate的常用操作: template.opsForValue() 操作字符串String template.opsForList() 操作列表List template.opsForSet() 操作集合Set template.opsForHash() 操作散列Hash template.opsForZset() 操作有序集合Zset template.opsForGeo() 操作地理位置geo template.opsForHyperLogLog() 操作HyperLogLog数据类型 除了基本的操作,我们常用的方法都可以直接通过redisTemplate操作,比如事务,基本的curd等 */ // 获取Redis连接对象 /*RedisConnection redisConnection = template.getConnectionFactory().getConnection(); redisConnection.flushDb(); // 清空当前数据内容 redisConnection.flushAll(); // 清空所有数据库内容*/ template.opsForValue().set("message","Hello World !"); String message = template.opsForValue().get("message"); System.out.println(message); } }
输出:
5、序列化问题
以上代码,如果我们对应的值存的是中文,在远程服务里会进行转义。这不是我们希望看到的。为什么会转义呢?
源码分析(RedisTemplate):
// 序列化的相关配置,可自己查看源码 @SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null; @SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null; @SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null; @SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null; // 默认的序列化配置,这里我们可以看到,当默认序列化(defaultSerializer)等于null的时候 // RedisTemplate默认使用的是jdk的序列化机制(JdkSerializationRedisSerializer) if (defaultSerializer == null) { defaultSerializer = new JdkSerializationRedisSerializer( classLoader != null ? classLoader : this.getClass().getClassLoader()); }
如果set一个没有序列化的Java对象,会报错!
6、编写我们自己的 RedisTemplate 解决序列化出现的问题
@Configuration public class RedisConfig { // 编写我们自己的 RedisTemplate @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { // 我们为了开发方便,直接使用<String,Object>泛型 RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); // 序列化配置 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // String序列化的配置 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化 template.setKeySerializer(stringRedisSerializer); // Hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value采用Jackson2JsonRedisSerializer的序列化方式 template.setValueSerializer(jackson2JsonRedisSerializer); // Hash的value也采用jackson2JsonRedisSerializer的序列化方式 template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
7.2、Redis工具类的撰写
在实际开发过程中,我们操作Redis时,不可能每次都写opsForXXX,这是非常繁琐费时间的,我们要常用的操作封装到一个工具类里,方便我们调用Redis里的命令和在多个项目里实现代码的复用!
参考博客1:https://www.cnblogs.com/zeng1994/p/03303c805731afc9aa9c60dbbd32a323.html
参考博客2:https://www.cnblogs.com/zhzhlong/p/11434284.html
参考博客3:https://www.cnblogs.com/laizhenghua/articles/13922662.html
测试:
// 使用自己封装的Redis工具类 @Autowired private RedisUtil redisUtil; // 编写测试方法 @Test public void redisUtilTest(){ redisUtil.set("name","howie"); System.out.println("debug ==> " + redisUtil.get("name")); }
所有Redis操作,对于Java开发人员来说,是非常简单,重要的是去理解Redis的思想和每一种数据结构的用处和作用场景!
8、redis.conf配置文件详解
8.1、基本配置知识
1、单位
# 1k => 1000 bytes # 1kb => 1024 bytes # 1m => 1000000 bytes # 1mb => 1024*1024 bytes # 1g => 1000000000 bytes # 1gb => 1024*1024*1024 bytes # # units are case insensitive so 1GB 1Gb 1gB are all the same.
配置文件 unit 单位对大小写不敏感
2、包含,多个配置文件可组合在一起
################################## INCLUDES ################################### # 包含 # Include one or more other config files here. This is useful if you # have a standard template that goes to all Redis servers but also need # to customize a few per-server settings. Include files can include # other files, so use this wisely. # # Note that option "include" won't be rewritten by command "CONFIG REWRITE" # from admin or Redis Sentinel. Since Redis always uses the last processed # line as value of a configuration directive, you'd better put includes # at the beginning of this file to avoid overwriting config change at runtime. # # If instead you are interested in using includes to override configuration # options, it is better to use include as the last line. # 修改配置如下 # include /path/to/local.conf # include /path/to/other.conf
就好比我们学习的Spring: import、include
3、网络
################################## NETWORK ##################################### # By default, if no "bind" configuration directive is specified, Redis listens # for connections from all available network interfaces on the host machine. # It is possible to listen to just one or multiple selected interfaces using # the "bind" configuration directive, followed by one or more IP addresses.
bind 127.0.0.1 # 绑定IP protected-mode yes # 是否受保护 port 6379 # 端口设置
4、通用设置
################################# GENERAL ##################################### # By default Redis does not run as a daemon. Use 'yes' if you need it. # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize yes # 是否以守护进程的方式运行,默认是no pidfile /var/run/redis_6379.pid # 如果以后台的方式运行,我们需要制定一个 pid 文件! # ===== 日志 ===== # Specify the server verbosity level. # This can be one of: # debug (a lot of information, useful for development/testing) # verbose (many rarely useful info, but not a mess like the debug level) # notice (moderately verbose, what you want in production probably) 生产环境适用 # warning (only very important / critical messages are logged) loglevel notice # 日志级别 logfile "" # 日志的文件位置名 databases 16 # 数据库的数量,默认是 16 个 always-show-logo yes # 是否总是显示logo
5、快照,持久化时使用
################################ SNAPSHOTTING ################################ # # Save the DB on disk:
在规定时间内,执行了多少次操作,则会持久化到文件 .rdb .aof
Redis是持久化数据库,如果没有持久化,那么数据就会断电即失!
# 如果900s内,如果至少有一个1 key 进行了修改,就会进行持久化操作 save 900 1 # 如果300s内,如果至少10 key 进行了修改,就会进行持久化操作 save 300 10 # 如果60s内,如果至少10000 key 进行了修改,就会进行持久化操作 save 60 10000 # 实际开发中,我们会自己设置持久化规则,后面会讲 stop-writes-on-bgsave-error yes # 持久化出错时,是否继续工作 rdbcompression yes # 是否压缩rdb文件,此时需要消耗CPU资源 rdbchecksum yes # 保存rdb文件时,进行错误的检查校验 dir ./ # rdb 文件保存的目录
6、主从复制
################################# REPLICATION ################################# # Master-Replica replication. Use replicaof to make a Redis instance a copy of # another Redis server. A few things to understand ASAP about Redis replication. # # +------------------+ +---------------+ # | Master | ---> | Replica | # | (receive writes) | | (exact copy) | # +------------------+ +---------------+ # === 后面主从复制在介绍 ===
7、安全相关
################################## SECURITY ################################### # Warning: since Redis is pretty fast, an outside user can try up to # 1 million passwords per second against a modern box. This means that you # should use very strong passwords, otherwise they will be very easy to break. # Note that because the password is really a shared secret between the client # and the server, and should not be memorized by any human, the password # can be easily a long string from /dev/urandom or whatever, so by using a # long and unguessable password no brute force attack will be possible.
可以在这里设置密码(一般不直接修改配置文件,使用命令行设置),默认是没有密码!
# 设置密码,设置完后,记得重启Redis 127.0.0.1:6379> config set requirepass "123456" OK # 设置以后所有命令都需要登录才可以使用 127.0.0.1:6379> shutdown (error) NOAUTH Authentication required. # 登录 127.0.0.1:6379> auth 123456 # 验证服务器命令 OK # 获取密码 127.0.0.1:6379> config get requirepass 1) "requirepass" 2) "123456"
8、aof配置
############################## APPEND ONLY MODE ############################### # By default Redis asynchronously dumps the dataset on disk. This mode is # good enough in many applications, but an issue with the Redis process or # a power outage may result into a few minutes of writes lost (depending on # the configured save points).
appendonly no # 默认是不开启 aof模式的,默认是rdb模式持久化数据,大多数情况 rdb已经够用了! appendfilename "appendonly.aof" # 持久化文件的名字 # appendfsync always # 每次修改都会 sync,可能会导致速度慢(消耗性能) appendfsync everysec # 每秒执行一次 sync,可能会丢失这一秒的数据 # appendfsync no # 不同步,这个时候操作系统自己同步数据,速度较快
8.2、配置文件命令
所有配置都可以通过 config 命令查看(get)和设置(set)!
# 查看配置信息语法 config get xxx # 例子:查看数据库数量 127.0.0.1:6379> config get databases 1) "databases" 2) "16" # 设置配置信息语法 config set xxx "xxx" # 实例:设置访问密码 127.0.0.1:6379> config set requirepass "123456" OK
9、Redis数据持久化
9.1、RDB(Redis Data Base)
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。所以Redis提供了持久化功能!
1、什么是RDB ?
在主从复制中,rdb是备用的,在从机里面!
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。Redis会单独创建( fork )一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
默认的就是RDB模式,一般情况下一般不需要修改这个配置!
RDB保存的文件是 dump.rdb。在配置文件快照(sna)里进行配置!
# The filename where to dump the DB dbfilename dump.rdb