Redis4

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis4

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
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6月前
|
存储 JSON NoSQL
redis中的value
需要注意的是,redis中的value是以二进制形式存储的,因此在存储和读取数据时需要进行序列化和反序列化操作。常用的序列化方式包括JSON、Protobuf、Msgpack等。示例代码如下
45 0
|
8月前
|
存储 缓存 NoSQL
|
9月前
|
存储 缓存 NoSQL
Redis5
Redis5
101 0
|
9月前
|
存储 消息中间件 缓存
了解redis
了解redis
49 0
|
10月前
|
NoSQL Redis 数据库
什么是Redis
Redis,即远程字典服务,是一个开源的使用ANSI C语言编写,支持网络,可基于内存亦可持久化的日志型,Key-Value数据库。类似于map
44 0
|
11月前
|
NoSQL 安全 Unix
Redis (必看)
Redis 学习点滴 知识分享
62 0
|
12月前
|
存储 消息中间件 NoSQL
|
存储 消息中间件 缓存
Redis的使用
Redis的使用
242 0
Redis的使用
|
存储 缓存 NoSQL
Redis
Redis
91 0
|
存储 消息中间件 缓存
Redis可以做哪些事?
Redis是一种基于键值对的NoSQL数据库,它的值主要由string(字符串),hash(哈希),list(列表),set(集合),zset(有序集合)五种基本数据结构构成,除此之外还支持一些其他的数据结构和算法。
178 0