# Redis 缓存

# 安装

在 Maven 工程中使用

  <dependency>
        <groupId>com.zhengcheng</groupId>
        <artifactId>zc-cache-spring-boot-starter</artifactId>
  </dependency>
1
2
3
4

Lettuce [ˈletɪs]

高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器

SpringBoot2.x默认采用Lettuce客户端来连接Redis服务端的。

# 属性配置

spring.redis.database = 0
spring.redis.host = 127.0.0.1
spring.redis.port = 6379
spring.redis.password = 123456
spring.redis.timeout = 20000
spring.redis.lettuce.pool.max-active = 8
spring.redis.lettuce.pool.max-idle = 8
spring.redis.lettuce.pool.min-idle = 0
1
2
3
4
5
6
7
8

# 使用

# mGet 批量获取值

List<String> keys = new ArrayList<>();
//初始keys
List<YourObject> list = this.redisTemplate.opsForValue().multiGet(keys);
1
2
3

注意:如果对应的key没有值,则YourObjectNULL;也就是说,list不可能是NULL,但是YourObject可能为NULL

# PipeLine

List<YourObject> list = this.redisTemplate.executePipelined(new RedisCallback<YourObject>() {
    @Override
    public YourObject doInRedis(RedisConnection connection) throws DataAccessException {
        StringRedisConnection conn = (StringRedisConnection)connection;
        for (String key : keys) {
            conn.get(key);
        }
        return null;
    }
1
2
3
4
5
6
7
8
9

mGet 与 PipeLine 的区别: 它们底层都是用到execute方法,multiGet是一条命令直接传给Redis,而executePipelined实际上是一条或多条命令,但是共用一个连接

# execute 方法

/**
	 * Executes the given action object within a connection that can be exposed or not. Additionally, the connection can
	 * be pipelined. Note the results of the pipeline are discarded (making it suitable for write-only scenarios).
	 * 
	 * @param <T> return type
	 * @param action callback object to execute
	 * @param exposeConnection whether to enforce exposure of the native Redis Connection to callback code
	 * @param pipeline whether to pipeline or not the connection for the execution
	 * @return object returned by the action
	 */
	public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		Assert.notNull(action, "Callback object must not be null");

		RedisConnectionFactory factory = getConnectionFactory();
		RedisConnection conn = null;
		try {

			if (enableTransactionSupport) {
				// only bind resources in case of potential transaction synchronization
				conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
			} else {
				conn = RedisConnectionUtils.getConnection(factory);
			}

			boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);

			RedisConnection connToUse = preProcessConnection(conn, existingConnection);

			boolean pipelineStatus = connToUse.isPipelined();
			if (pipeline && !pipelineStatus) {
				connToUse.openPipeline();
			}

			RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));
			T result = action.doInRedis(connToExpose);

			// close pipeline
			if (pipeline && !pipelineStatus) {
				connToUse.closePipeline();
			}

			// TODO: any other connection processing?
			return postProcessResult(result, connToUse, existingConnection);
		} finally {
			RedisConnectionUtils.releaseConnection(conn, factory);
		}
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# CacheManager

zhengcheng@EnableCaching默认是使用 CacheType.SIMPLE

如果要开启caffeine ,需要增加属性配置,具体如下:

spring.cache.type = caffeine
spring.cache.caffeine.spec = initialCapacity=10,maximumSize=200,expireAfterWrite=3s
1
2

# redisson

  • 1. Add redisson-spring-boot-starter dependency into your project:
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
1
2
3
4

Downgrade redisson-spring-data module if necessary to support required Spring Boot version:

redisson-spring-data
module name
Spring Boot
version
redisson-spring-data-16 1.3.x
redisson-spring-data-17 1.4.x
redisson-spring-data-18 1.5.x
redisson-spring-data-20 2.0.x
redisson-spring-data-21 2.1.x
redisson-spring-data-22 2.2.x
redisson-spring-data-23 2.3.x

目前Spring Boot version 2.1.x对应的redisson-spring-boot-starter最高版本是3.11.5

  • 2. Add settings into application.settings file

Common spring boot settings or Redisson settings could be used.

# common spring boot settings

spring:
  redis:
    database: 
    host:
    port:
    password:
    ssl: 
    timeout:
    cluster:
      nodes:
    sentinel:
      master:
      nodes:

  # Redisson settings
    
  #path to config - redisson.yaml
  redisson: 
    file: classpath:redisson.yaml
    config: |
      clusterServersConfig:
        idleConnectionTimeout: 10000
        connectTimeout: 10000
        timeout: 3000
        retryAttempts: 3
        retryInterval: 1500
        failedSlaveReconnectionInterval: 3000
        failedSlaveCheckInterval: 60000
        password: null
        subscriptionsPerConnection: 5
        clientName: null
        loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
        subscriptionConnectionMinimumIdleSize: 1
        subscriptionConnectionPoolSize: 50
        slaveConnectionMinimumIdleSize: 24
        slaveConnectionPoolSize: 64
        masterConnectionMinimumIdleSize: 24
        masterConnectionPoolSize: 64
        readMode: "SLAVE"
        subscriptionMode: "SLAVE"
        nodeAddresses:
        - "redis://127.0.0.1:7004"
        - "redis://127.0.0.1:7001"
        - "redis://127.0.0.1:7000"
        scanInterval: 1000
        pingConnectionInterval: 0
        keepAlive: false
        tcpNoDelay: false
      threads: 16
      nettyThreads: 32
      codec: !<org.redisson.codec.FstCodec> {}
      transportMode: "NIO"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  • 3. Use Redisson through spring bean with RedissonClient interface or RedisTemplate/ReactiveRedisTemplate objects

# Reentrant Lock (可重入锁)

    String lockName = StrUtil.format("zmbiz-brain-record-b-update-question-{}", question.getId());
    // 可重入锁(Reentrant Lock)
    RLock lock = redissonClient.getLock(lockName);
    try {
          // 获取锁
          if (lock.tryLock(5, 3, TimeUnit.SECONDS)) {
              
                // TODO Something
          }
    } catch (Exception e) {
           log.error(e.getMessage(), e);
    } finally {
       // 释放锁
       if (lock.isLocked() && lock.isHeldByCurrentThread()) {
           lock.unlock();
       }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# RAtomicLong

作用:分布式下对数据中的Long类型进行原子性操作。

获取自增长ID示例代码如下:

 RAtomicLong rAtomicLong = redissonClient.getAtomicLong(CacheConstant.getVacQrCodeLessonIdIncKey());

 rAtomicLong.incrementAndGet()
1
2
3

参考文档

Last Updated: 2 years ago