• Redis快速上手篇(三)(事务+Idea的连接和使用)


    Redis事务

    可以一次执行多个命令,本质是一组命令的集合。一个事务中的 所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。

    单独的隔离的操作

    官网说明

    https://redis.io/docs/interact/transactions/

    MULTI、EXEC、DISCARD、WATCH。这四个指令构成了 redis 事务处理的基础。

            1.MULTI 用来组装一个事务;将命令存放到一个队列里面

            2.EXEC 用来执行一个事务;相当于mysql的//commit

            3.DISCARD 用来取消一个事务;相当于mysql的//rollback

            4.WATCH 用来监视一些 key,一旦这些 key 在事务执行之前被改变,则取消事务的执行。

    结束后统一执行

    有关事务,经常会遇到的是两类错误:

    调用 EXEC 之前的错误 如语法错误,事务不会被执行

    调用 EXEC 之后的错误 如重复建,事务不会理睬错误(不会影响接下来的其他命令的执行)

    WATCH

    “WATCH”可以帮我们实现类似于“乐观锁”的效果,即 CAS(check and set)。

    WATCH 本身的作用是“监视 key 是否被改动过”,而且支持同时监视多个 key,只要还没真正触发事务,WATCH 都会尽职尽责的监视,一旦发现某个 key 被修改了,在执行 EXEC 时就会返回 nil,表示事务无法触发。

    在 multi 之前 set year 修改了值所以 nil

    事务回滚(discard)

    事务冲突

    比如涉及金钱的操作,导致金额负数

    解决方案

    悲观锁(Pessimistic Lock)

    顾名思义,就是很悲观

    每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁

    这样别人想拿这个数据就会block直到它拿到锁。

    传统的关系型数据库里边就用到了很多这种锁机制,

    比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

    每次都会上锁影响效率

    乐观锁(Optimistic Lock)

    顾名思义,就是很乐观

    每次去拿数据的时候都认为别人不会修改,所以不会上锁,

    但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,

    可以使用版本号等机制。乐观锁适用于多读的应用类型

    这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

    redis与idea的连接

    ssm

    添加redis的依赖

    1. <dependency>
    2. <groupId>redis.clients</groupId>
    3. <artifactId>jedis</artifactId>
    4. <version>3.2.0</version>
    5. </dependency>

    Jedis jds = new Jedis("IP")

    jds.auth("密码")

    jds.select(数据库)

    spring boot

    加入redis的依赖

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-data-redis</artifactId>
    4. </dependency>
    5. <dependency>
    6. <groupId>org.apache.commons</groupId>
    7. <artifactId>commons-pool2</artifactId>
    8. <version>2.6.0</version>
    9. </dependency>
    10. <dependency>
    11. <groupId>redis.clients</groupId>
    12. <artifactId>jedis</artifactId>
    13. </dependency>

    编写配置文件

    1. #设置reis的索引
    2. spring.redis.database=15
    3. #设置连接redis的密码
    4. spring.redis.password=yyl
    5. #设置的redis的服务器
    6. spring.redis.host=192.168.159.34
    7. #端口号
    8. spring.redis.port=6379
    9. #连接超时时间(毫秒)
    10. spring.redis.timeout=1800000
    11. #连接池最大连接数(使用负值表示没有限制)
    12. spring.redis.lettuce.pool.max-active=20
    13. #最大阻塞等待时间(负数表示没限制)
    14. spring.redis.lettuce.pool.max-wait=-1
    15. #连接池中的最大空闲连接
    16. spring.redis.lettuce.pool.max-idle=5
    17. #连接池中的最小空闲连接
    18. spring.redis.lettuce.pool.min-idle=0

    设置配置类

    1. package com.example.demo;
    2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
    3. import com.fasterxml.jackson.annotation.PropertyAccessor;
    4. import com.fasterxml.jackson.databind.ObjectMapper;
    5. import org.springframework.cache.CacheManager;
    6. import org.springframework.cache.annotation.CachingConfigurerSupport;
    7. import org.springframework.cache.annotation.EnableCaching;
    8. import org.springframework.context.annotation.Bean;
    9. import org.springframework.context.annotation.Configuration;
    10. import org.springframework.data.redis.cache.RedisCacheConfiguration;
    11. import org.springframework.data.redis.cache.RedisCacheManager;
    12. import org.springframework.data.redis.connection.RedisConnectionFactory;
    13. import org.springframework.data.redis.core.RedisTemplate;
    14. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    15. import org.springframework.data.redis.serializer.RedisSerializationContext;
    16. import org.springframework.data.redis.serializer.RedisSerializer;
    17. import org.springframework.data.redis.serializer.StringRedisSerializer;
    18. import java.time.Duration;
    19. @EnableCaching
    20. @Configuration
    21. public class RedisConfig extends CachingConfigurerSupport {
    22. /**
    23. * 连接池的设置
    24. *
    25. * @return
    26. */
    27. @Bean
    28. public JedisPoolConfig getJedisPoolConfig() {
    29. JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    30. return jedisPoolConfig;
    31. }
    32. /**
    33. * RedisTemplate
    34. * @param factory
    35. * @return
    36. */
    37. @Bean
    38. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    39. RedisTemplate<String, Object> template = new RedisTemplate<>();
    40. RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    41. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    42. ObjectMapper om = new ObjectMapper();
    43. // 指定要序列化的域,field,getset,以及修饰符范围,ANY是都有包括private和public
    44. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    45. // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
    46. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    47. jackson2JsonRedisSerializer.setObjectMapper(om);
    48. template.setConnectionFactory(factory);
    49. //key序列化方式
    50. template.setKeySerializer(redisSerializer);
    51. //value序列化
    52. template.setValueSerializer(jackson2JsonRedisSerializer);
    53. //value hashmap序列化
    54. template.setHashValueSerializer(jackson2JsonRedisSerializer);
    55. return template;
    56. }
    57. /**
    58. * 缓存处理
    59. * @param factory
    60. * @return
    61. */
    62. @Bean
    63. public CacheManager cacheManager(RedisConnectionFactory factory) {
    64. RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    65. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    66. //解决查询缓存转换异常的问题
    67. ObjectMapper om = new ObjectMapper();
    68. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    69. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    70. jackson2JsonRedisSerializer.setObjectMapper(om);
    71. // 配置序列化(解决乱码的问题),过期时间600
    72. RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    73. .entryTtl(Duration.ofSeconds(600))
    74. .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
    75. .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
    76. .disableCachingNullValues();
    77. RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
    78. .cacheDefaults(config)
    79. .build();
    80. return cacheManager;
    81. }
    82. }

    编写测试代码

    spring-data-redis针对jedis提供了如下功能:

    1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类

    2. RedisTemplate 对五种数据结构分别定义了操作

    操作字符串

    redisTemplate.opsForValue();

    操作hash

    redisTemplate.opsForHash();

    操作list

    redisTemplate.opsForList();

    操作set

    redisTemplate.opsForSet();

    操作有序set

    redisTemplate.opsForZSet();

    String类型与List类型

    Set类型
    1. 添加元素
    2. redisTemplate.opsForSet().add(key, values)
    3. 移除元素(单个值、多个值)
    4. redisTemplate.opsForSet().remove(key, values)
    5. 删除并且返回一个随机的元素
    6. redisTemplate.opsForSet().pop(key)
    7. 获取集合的大小
    8. redisTemplate.opsForSet().size(key)
    9. 判断集合是否包含value
    10. redisTemplate.opsForSet().isMember(key, value)
    11. 获取两个集合的交集(key对应的无序集合与otherKey对应的无序集合求交集)
    12. redisTemplate.opsForSet().intersect(key, otherKey)
    13. 获取多个集合的交集(Collection var2)
    14. redisTemplate.opsForSet().intersect(key, otherKeys)
    15. key集合与otherKey集合的交集存储到destKey集合中(其中otherKey可以为单个值或者集合)
    16. redisTemplate.opsForSet().intersectAndStore(key, otherKey, destKey)
    17. key集合与多个集合的交集存储到destKey无序集合中
    18. redisTemplate.opsForSet().intersectAndStore(key, otherKeys, destKey)
    19. 获取两个或者多个集合的并集(otherKeys可以为单个值或者是集合)
    20. redisTemplate.opsForSet().union(key, otherKeys)
    21. key集合与otherKey集合的并集存储到destKey中(otherKeys可以为单个值或者是集合)
    22. redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey)
    23. 获取两个或者多个集合的差集(otherKeys可以为单个值或者是集合)
    24. redisTemplate.opsForSet().difference(key, otherKeys)
    25. 差集存储到destKey中(otherKeys可以为单个值或者集合)
    26. redisTemplate.opsForSet().differenceAndStore(key, otherKey, destKey)
    27. 随机获取集合中的一个元素
    28. redisTemplate.opsForSet().randomMember(key)
    29. 获取集合中的所有元素
    30. redisTemplate.opsForSet().members(key)
    31. 随机获取集合中count个元素
    32. redisTemplate.opsForSet().randomMembers(key, count)
    33. 获取多个key无序集合中的元素(去重),count表示个数
    34. redisTemplate.opsForSet().distinctRandomMembers(key, count)
    35. 遍历set类似于Interator(ScanOptions.NONE为显示所有的)
    36. redisTemplate.opsForSet().scan(key, options)
    Hash类型
    1. Long delete(H key, Object... hashKeys);
    2. 删除给定的哈希hashKeys
    3. System.out.println(template.opsForHash().delete("redisHash","name"));
    4. System.out.println(template.opsForHash().entries("redisHash"));
    5. 1
    6. {class=6, age=28.1}
    7. Boolean hasKey(H key, Object hashKey);
    8. 确定哈希hashKey是否存在
    9. System.out.println(template.opsForHash().hasKey("redisHash","666"));
    10. System.out.println(template.opsForHash().hasKey("redisHash","777"));
    11. true
    12. false
    13. HV get(H key, Object hashKey);
    14. 从键中的哈希获取给定hashKey的值
    15. System.out.println(template.opsForHash().get("redisHash","age"));
    16. 26
    17. Set<HK> keys(H key);
    18. 获取key所对应的散列表的key
    19. System.out.println(template.opsForHash().keys("redisHash"));
    20. //redisHash所对应的散列表为{class=1, name=666, age=27}
    21. [name, class, age]
    22. Long size(H key);
    23. 获取key所对应的散列表的大小个数
    24. System.out.println(template.opsForHash().size("redisHash"));
    25. //redisHash所对应的散列表为{class=1, name=666, age=27}
    26. 3
    27. void putAll(H key, Map<? extends HK, ? extends HV> m);
    28. 使用m中提供的多个散列字段设置到key对应的散列表中
    29. Map<String,Object> testMap = new HashMap();
    30. testMap.put("name","666");
    31. testMap.put("age",27);
    32. testMap.put("class","1");
    33. template.opsForHash().putAll("redisHash1",testMap);
    34. System.out.println(template.opsForHash().entries("redisHash1"));
    35. {class=1, name=jack, age=27}
    36. void put(H key, HK hashKey, HV value);
    37. 设置散列hashKey的值
    38. template.opsForHash().put("redisHash","name","666");
    39. template.opsForHash().put("redisHash","age",26);
    40. template.opsForHash().put("redisHash","class","6");
    41. System.out.println(template.opsForHash().entries("redisHash"));
    42. {age=26, class=6, name=666}
    43. List<HV> values(H key);
    44. 获取整个哈希存储的值根据密钥
    45. System.out.println(template.opsForHash().values("redisHash"));
    46. [tom, 26, 6]
    47. Map<HK, HV> entries(H key);
    48. 获取整个哈希存储根据密钥
    49. System.out.println(template.opsForHash().entries("redisHash"));
    50. {age=26, class=6, name=tom}
    51. Cursor<Map.Entry<HK, HV>> scan(H key, ScanOptions options);
    52. 使用Cursorkey的hash中迭代,相当于迭代器。
    53. Cursor<Map.Entry<Object, Object>> curosr = template.opsForHash().scan("redisHash",
    54. ScanOptions.ScanOptions.NONE);
    55. while(curosr.hasNext()){
    56. Map.Entry<Object, Object> entry = curosr.next();
    57. System.out.println(entry.getKey()+":"+entry.getValue());
    58. }
    59. age:27
    60. class:6
    61. name:666

    命令

    操作

    返回值

    hash.delete(H key, Object... hashKeys)

    删除,可以传入多个map的key【hdel】

    Long

    hash.hasKey(key, hashKey)

    查看hash中的某个hashKey是否存在【hexists】

    Boolean

    hash.get(key, hashKey)

    获取值【hget】

    Object(HV 泛型约束对象)

    hash.multiGet(H key, Collection hashKeys)

    批量获取集合中的key对应的值【hmget】

    List

    hash.increment(H key, HK hashKey, long delta)

    对值进行+(delta值)操作【】

    Long

    hash.increment(H key, HK hashKey, double delta)

    ~

    double

    hash.keys(key)

    返回map内hashKey的集合【hkeys】

    Set

    hash.lengthOfValue(H key, HK hashKey)

    返回查询键关联的值的长度,为null则返回0【hstrlen】

    Long

    hash.size(H key)

    获取hashKey的个数【hlen】

    Long

    hash.putAll(H key, Map m)

    相当于map的putAll【hmset】

    void

    hash.put(H key, HK hashKey, HV value)

    设置值,添加hashKey-value,hashKay相当于map的key 【hset】

    void

    hash.putIfAbsent(H key, HK hashKey, HV value)

    仅当hashKey不存在时设置值

    Boolean

    hash.values(key)

    返回value的集合【hvals】

    List

    hase.entries(H key)

    获取map【hgetall】

    Map

    hash.scan(H key, ScanOptions options)

    基于游标的迭代查询【hscan】

    Cursor>(返回的Cursor要手动关闭,见下面示例2)

    hash.getOperations()

    返回RedisOperation,它就是redis操作的接口

    RedisOperations

    ZSet类型
    1. Boolean add(K key, V value, double score);
    2. 新增一个有序集合,存在的话为false,不存在的话为true
    3. System.out.println(template.opsForZSet().add("zset1","zset-1",1.0));
    4. true
    5. Long add(K key, Set<TypedTuple<V>> tuples);
    6. 新增一个有序集合
    7. ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-5",9.6);
    8. ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-6",9.9);
    9. Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet>();
    10. tuples.add(objectTypedTuple1);
    11. tuples.add(objectTypedTuple2);
    12. System.out.println(template.opsForZSet().add("zset1",tuples));
    13. System.out.println(template.opsForZSet().range("zset1",0,-1));
    14. [zset-1, zset-2, zset-3, zset-4, zset-5, zset-6]
    15. Long remove(K key, Object... values);
    16. 从有序集合中移除一个或者多个元素
    17. System.out.println(template.opsForZSet().range("zset1",0,-1));
    18. System.out.println(template.opsForZSet().remove("zset1","zset-6"));
    19. System.out.println(template.opsForZSet().range("zset1",0,-1));
    20. [zset-1, zset-2, zset-3, zset-4, zset-5, zset-6]
    21. 1
    22. [zset-1, zset-2, zset-3, zset-4, zset-5]
    23. Long rank(K key, Object o);
    24. 返回有序集中指定成员的排名,其中有序集成员按分数值递增(从小到大)顺序排列
    25. System.out.println(template.opsForZSet().range("zset1",0,-1));
    26. System.out.println(template.opsForZSet().rank("zset1","zset-2"));
    27. [zset-2, zset-1, zset-3, zset-4, zset-5]
    28. 0 //表明排名第一
    29. Set<V> range(K key, long start, long end);
    30. 通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列
    31. System.out.println(template.opsForZSet().range("zset1",0,-1));
    32. [zset-2, zset-1, zset-3, zset-4, zset-5]
    33. Long count(K key, double min, double max);
    34. 通过分数返回有序集合指定区间内的成员个数
    35. System.out.println(template.opsForZSet().rangeByScore("zset1",0,5));
    36. System.out.println(template.opsForZSet().count("zset1",0,5));
    37. [zset-2, zset-1, zset-3]
    38. 3
    39. Long size(K key);
    40. 获取有序集合的成员数,内部调用的就是zCard方法
    41. System.out.println(template.opsForZSet().size("zset1"));
    42. 6
    43. Double score(K key, Object o);
    44. 获取指定成员的score值
    45. System.out.println(template.opsForZSet().score("zset1","zset-1"));
    46. 2.2
    47. Long removeRange(K key, long start, long end);
    48. 移除指定索引位置的成员,其中有序集成员按分数值递增(从小到大)顺序排列
    49. System.out.println(template.opsForZSet().range("zset2",0,-1));
    50. System.out.println(template.opsForZSet().removeRange("zset2",1,2));
    51. System.out.println(template.opsForZSet().range("zset2",0,-1));
    52. [zset-1, zset-2, zset-3, zset-4]
    53. 2
    54. [zset-1, zset-4]
    55. Cursor<TypedTuple<V>> scan(K key, ScanOptions options);
    56. 遍历zset
    57. Cursor<ZSetOperations.TypedTuple<Object>> cursor = template.opsForZSet().scan("zzset1", ScanOptions.NONE);
    58. while (cursor.hasNext()){
    59. ZSetOperations.TypedTuple<Object> item = cursor.next();
    60. System.out.println(item.getValue() + ":" + item.getScore());
    61. }
    62. zset-1:1.0
    63. zset-2:2.0
    64. zset-3:3.0
    65. zset-4:6.0

  • 相关阅读:
    spring MVC基础步骤
    计算机网络408 2017
    信创大潮下,产业金融路在何方?
    传输层和网络层的checksum区别,TCP cksum为何包含伪首部
    电子数据取证-流程与技术
    EtherCAT转Modbus-TCP协议网关与DCS连接的配置方法
    LeetCode 441. 排列硬币
    利用jar包构建Docker 镜像
    智华计算机终端保护检查系统使用笔记
    Node.js - nvm管理node.js版本
  • 原文地址:https://blog.csdn.net/Z15800020057/article/details/134012383