Redis的事务以及Jedis

122 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战

事务

redis事务:事物的本质相当于一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行的过程中,会按照顺序执行!一次性、顺序性、排他性。

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。 一个事务从开始到执行会经历以下三个阶段:
  • 开始事务。(MULTI)
  • 命令入队。
  • 执行事务(EXEC)

放弃事务(discard):放弃事务的命令执行后,队列中的命令都不会被执行!

事务中的某些命令出错,则事务里的所有的命令都不会执行,类似于Java的编译时异常

如果事务队列中存在语法性错误,那么执行命令的时候,其他命令是可以正常执行的,错误的命令会抛出异常!

监控

理解监控前先了解两个概念,乐观锁和悲观锁。

乐观锁:认为什么时候都不会出现问题,所以不会上锁,更新数据的时候回去判断一下,
        在此期间数据有没有被修改,更新之前获取version,更新的时候进行比较。
悲观锁:认为任何时候都会出现问题,做什么都加锁。

用watch命令来进行监视,监视money,没有被其他客户端修改时则事务执行成功,当被其他客户端修改时,事务执行失败。

Jedis

导入Jedis的依赖后,可通过Jedis的对象来操作redis,api的名称几乎完全和命令一样,这个可以查看文档也可以直接查看源码。

Springboot集成Redis

Springboot操作数据库:spring-data,Springboot2.X之后,由原来的Jedis替换成了lettuce

jedis:采用直连的方式,多个线程操作不安全,可以使用Jedis Pool连接池,更像BIO
lettuce:采用netty,实例可以再多个线程中共享,不存在线程不安全的情况,可以减少线程数据量,更像NIO模式。

对于RedisTemplate的使用,RedisTemplate用于操作不同的数据类型,API和Redis的指令差不多,除了基本的操作,常用的的方法也可以直接通过redisTemplate来操作

redisTemplate.opsForValue()操作字符串,类似String
redisTemplate.opsForList()操作List
redisTemplate.opsForHash()操作Hash
redisTemplate.opsForSet()操作Set
redisTemplate.opsForZSet()操作Zset
redisTemplate.opsForHyperLogLog()操作Hyperloglog
redisTemplate.opsForGeo()操作Georadius

RedisTemplate的部分源码:

 private boolean enableDefaultSerializer = true;
    @Nullable
    private RedisSerializer<?> defaultSerializer;
    @Nullable
    private ClassLoader classLoader;
    @Nullable
    private RedisSerializer keySerializer = null;
    @Nullable
    private RedisSerializer valueSerializer = null;
    @Nullable
    private RedisSerializer hashKeySerializer = null;
    @Nullable
    private RedisSerializer hashValueSerializer = null; //上面这些是序列化配置
    private RedisSerializer<String> stringSerializer = RedisSerializer.string();
.....
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
        boolean defaultUsed = false;
        if (this.defaultSerializer == null) {
            this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
        }//采用的是默认的序列化方式,JDK序列化,中文在命令行可能会被转义,一般使用可能会用Json来序列化

不序列化会发生错误:

自定义RedisTemplate,完成序列化的设置,已适应大多数的场景,自定义的RedisTemplate会覆盖原有的RedisTemplate:

@Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        //
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        
        //Json序列化配置
        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);
        
        //String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        
        //key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash的key采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        
        template.afterPropertiesSet();
        return template;
    }