redission读写锁解决db和缓存双写不一致

db和缓存双写不一致

多线程访问环境下,在更新完db后再去更新缓存,不加锁显而易见的就会出现缓存被覆盖的问题。

线程1修改完db去更新缓存的时候慢了一拍。
此时线程2线程1之后修改完db更新成功了缓存。
此时线程1更新缓存的操作恢复了,然后去更新了缓存。那么此时的缓存其实是个脏数据。

有什么办法呢?

方案一

直接加redission的普通Rlock分布式锁,比如对一个sku的缓存更新都排着队串行操作。这样也行,但是性能损失大。

方案二

Redisson其实还有读写锁.
操作过db的都知道,写锁是互斥的,读锁是可以大家一起加的。生产中实际80%大多都是读操作,剩下20%才是写。

下面来上demo

redission依赖

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

配置类

package com.fchan.espractice.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRedissionConfig {

    @Bean
    public RedissonClient redissionClient() {
        Config config = new Config();

        //单机模式
        config.useSingleServer()
                .setAddress("redis://192.168.56.101:36379")
                //.setPassword("111")
                .setDatabase(1);

        //集群模式
        /*config.useClusterServers()
                .addNodeAddress("redis://192.168.56.101:36379")
                .addNodeAddress("redis://192.168.56.102:36379")
                .addNodeAddress("redis://192.168.56.103:36379")
                .setPassword("1111111")
                .setScanInterval(5000);*/

        //哨兵模式
        /*config.useSentinelServers().addSentinelAddress("redis://ip1:port1",
                "redis://ip2:port2",
                "redis://ip3:port3")
                .setMasterName("mymaster")
                .setPassword("password")
                .setDatabase(0);*/

        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }



}

测试读写锁
测试发现同一个key读锁可以重复添加,但是在读锁还没释放的时候,加写锁是会被阻塞的。当这个key的读锁都释放完了写锁才能加上。一旦加上写锁,那么其他的写锁和读锁就会被阻塞了。

比如扣减库存场景,并发读下来,然后并发扣减,可能会有扣减失败的,之前读的时候还有,扣减的时候就没有库存了。

@GetMapping("addReadLock")
public void addReadLock(@RequestParam("key") String key){
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(key);
    RLock lock = readWriteLock.readLock();
    lock.lock();
}

@GetMapping("releaseReadLock")
public void releaseReadLock(@RequestParam("key") String key){
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(key);
    RLock lock = readWriteLock.readLock();
    lock.unlock();
}

@GetMapping("addWriteLock")
public void addWriteLock(@RequestParam("key") String key){
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(key);
    RLock lock = readWriteLock.writeLock();
    lock.lock();
}

@GetMapping("releaseWriteLock")
public void releaseWriteLock(@RequestParam("key") String key){
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(key);
    RLock lock = readWriteLock.writeLock();
    lock.unlock();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值