谷粒商城:Redisson

发布于:2025-04-03 ⋅ 阅读:(17) ⋅ 点赞:(0)

目录

Redisson

整合Redisson

 RLock

RReadWriteLock

RSemaphore

RCountDownLatch

优化三级分类缓存

缓存一致性问题

双写模式

失效模式

脏数据解决


Redisson

提供redis分布式锁(Distributed locks with Redis)的java客户端

整合Redisson

引入

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.12.0</version>
        </dependency>

程序化配置

@Configuration
public class RedissonConfig {
    @Value("${spring.redis.host}"+":"+"${spring.redis.port}")
    private String singleAddress;
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson() throws IOException {
        Config config = new Config();
        /*
          SingleServer() 单节点模式
          redis:// redis 连接协议
         */
        config.useSingleServer()
                .setAddress("redis://"+singleAddress);

        return Redisson.create(config);
    }
}

 RLock

可重入锁(Reentrant Lock)它允许同一个线程多次获取同一把锁而不会产生死锁。

RLock lock = redisson.getLock("myLock");

// 尝试获取锁,最多等待10秒,锁有效期30秒
boolean res = lock.tryLock(10, 30, TimeUnit.SECONDS);
if (res) {
    try {
        // 业务代码
    } finally {
        lock.unlock();
    }
}
  1. 可重入性:同一线程可多次获取同一把锁

  2. 锁续期:内置看门狗机制自动续期

  3. 公平锁:支持公平锁和非公平锁

  4. 锁释放:确保只有锁持有者能释放锁


RReadWriteLock

读写锁,它允许多个读操作同时进行,但写操作是排他的。

RReadWriteLock rwLock = redisson.getReadWriteLock("myReadWriteLock");
RLock readLock = rwLock.readLock();  // 获取读锁
RLock writeLock = rwLock.writeLock(); // 获取写锁
writeLock.lock();  // 先获取写锁
try {
    // 写操作...
    
    // 保持写锁的同时获取读锁(锁降级)
    readLock.lock();
    try {
        // 读操作...
    } finally {
        // 注意:这里不能释放写锁
    }
    
    // 可以继续持有写锁做其他操作
} finally {
    writeLock.unlock();  // 最后释放写锁
    // 此时仍持有读锁
}
  1. 读写分离

    • 多个线程可以同时持有读锁

    • 写锁是排他的,有写锁时不能有读锁或其他写锁

  2. 可重入性

    • 读锁和写锁都支持可重入

    • 同一线程可以多次获取同一把读锁或写锁

  3. 锁降级

    • 支持将写锁降级为读锁

    • 但不支持读锁升级为写锁(会死锁)

  4. 公平性选择

    • 支持公平和非公平两种模式


RSemaphore

 信号量,它允许多个线程/进程在分布式环境中协调对共享资源的访问

// 获取信号量实例(初始许可数为5)
RSemaphore semaphore = redisson.getSemaphore("mySemaphore");
semaphore.trySetPermits(5);  // 初始化许可数量

// 获取1个许可(阻塞直到可用)
semaphore.acquire();

try {
    // 访问受限资源
    accessLimitedResource();
} finally {
    // 释放许可
    semaphore.release();
}

  1. 资源限制:控制同时访问特定资源的线程/进程数量

  2. 分布式支持:跨JVM、跨服务器的协调能力

  3. 公平性选择:支持公平和非公平两种模式

  4. 可重入:支持同一线程多次获取许可

  5. 超时机制:支持尝试获取许可的超时设置

典型应用场景

  1. 限流控制:限制系统并发请求数

  2. 资源池管理:如数据库连接池控制

  3. 任务调度:限制同时执行的任务数量

  4. API访问限制:控制第三方API调用频率


RCountDownLatch

闭锁,它允许一个或多个线程等待其他线程完成操作后再继续执行。

RCountDownLatch latch = redisson.getCountDownLatch("myLatch");

// 初始化计数器为5
latch.trySetCount(5);

// 减少计数器(每个工作线程完成后调用)
latch.countDown();

//获取当前计数
long remaining = latch.getCount();

// 等待计数器归零(阻塞)
latch.await();

// 带超时的等待
boolean reached = latch.await(10, TimeUnit.SECONDS);

  1. 一次性使用:计数器归零后不能重置(与JDK的CountDownLatch一致)

  2. 等待/通知机制:线程可以等待计数器归零

  3. 可视化监控:可通过Redis直接查看当前计数状态

典型应用场景

  1. 分布式任务同步:等待多个分布式任务完成

  2. 系统初始化:等待所有服务初始化完成

  3. 批量处理:等待所有子任务处理完成

  4. 测试协调:分布式测试中的线程协调


优化三级分类缓存

    @Override
    public Map<String, List<Level2CategoryVo>> getLevel2AndLevel3Category() {
        //1.先从缓存中获取 catalogJson
        ValueOperations<String,String> valueOperations = redisTemplate.opsForValue();
        String catalogJson = valueOperations.get("catalogJson");
        Map<String, List<Level2CategoryVo>> res = null;
        if(StringUtils.isEmpty(catalogJson)){
            //缓存中无对应数据,查询数据库
            res = getCatalogJsonFromDBWithRedissonLock();
        }else{
            res = JSON.parseObject(catalogJson,new TypeReference<Map<String, List<Level2CategoryVo>> >(){});
        }
        return res;
    }

    /**
     * 获取 Redisson 分布式锁,查询数据库
     * @return
     */
    private Map<String, List<Level2CategoryVo>> getCatalogJsonFromDBWithRedissonLock(){
        Map<String, List<Level2CategoryVo>> res = null;
        RLock lock = redisson.getLock("CatalogJson-Lock");
        lock.lock();
        //成功获取到锁
        try {
            res = getCatalogJsonFromDB();
        }finally {
            lock.unlock();
        }
        return res;
    }

缓存一致性问题

双写模式

修改数据库,并修改缓存。

    失效模式

    修改数据库后,删除缓存,下一次查询时缓存数据。

    脏数据解决

    俩种模式都会产生暂时的脏数据,解决方案:

    1. 读写锁
    2. 过期时间,保证最终一致性
    3. 一致性要求高的数据,不存入缓存,应直接查询数据库


    网站公告

    今日签到

    点亮在社区的每一天
    去签到