Redisの過剰販売の問題を解決する

1つ目:同期を使用する(単一のtomcatにのみ適用可能)

@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/deduct")
    public String toDeduct(){
    
    
        synchronized (this) {
    
    
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if (stock > 0) {
    
    
                Long stock1 = stringRedisTemplate.opsForValue().decrement("stock");
                System.out.println("扣减成功,剩余库存:" + stock1);
            }else{
    
    
                System.out.println("扣减失败,库存不足");
            }
            return "end";
        }
    }

2番目:SETNXコマンドを使用する(複数のtomcat)

 @GetMapping("/deduct_stock")
    public String deductStock() throws InterruptedException {
    
    
        String lockKey = "lockKey";
        //设计唯一key值防止锁失效问题
        String clientId = UUID.randomUUID().toString();
        //设计锁超时时间,防止服务器宕机时锁没有释放掉(finally语句没有执行)
        Boolean result = stringRedisTemplate.opsForValue().
                setIfAbsent(lockKey, clientId, 10, TimeUnit.SECONDS);//jedis.setnx(key,value);
        //若键 key 已经存在, 则 SETNX 命令不做任何动作。result==false
        if (!result) {
    
    
            return "正在排队。。。";
        }
        try {
    
    
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if (stock > 0) {
    
    
                Long realStock = stringRedisTemplate.opsForValue().decrement("stock");
                System.out.println("扣减成功,剩余库存:" + realStock);
            }else{
    
    
                System.out.println("扣减失败,库存不足");
            }
        } finally {
    
    
            //防止锁失效问题,在多线程的情况下,每个线程只释放自己创建的锁,线程之间互不干预。
            if(clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
    
    
                stringRedisTemplate.delete(lockKey);
            }
        }
        return "end";
    }

3番目のタイプ:Redissionフレームワークを使用します(原則は2番目のタイプと同じです)

1.構成クラスを構成します

@Configuration
public class RedissonConfig {
    
    

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private String port;

    @Value("${spring.redis.password}")
    private String password;

    @Bean
    public RedissonClient getRedisson(){
    
    
        Config config = new Config();
        config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password);
        //添加主从配置
//      config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""});
        return Redisson.create(config);
    }
}
@GetMapping("/deduct_stock1")
    public String deductStock1(){
    
    
        String lockKey = "lockKey";
        RLock redissonLock = redisson.getLock(lockKey);
        try {
    
    
            redissonLock.lock();
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if (stock > 0) {
    
    
                Long realStock = stringRedisTemplate.opsForValue().decrement("stock");
                System.out.println("扣减成功,剩余库存:" + realStock);
            }else{
    
    
                System.out.println("扣减失败,库存不足");
            }
        } finally {
    
    
            redissonLock.unlock();
        }
        return "end";
    }

再分配の原則:

RedissionはLuaスクリプトを使用し、実装の原則は2番目のスクリプトと同様です。
mysqlの低速クエリなどのようにビジネスコードの処理時間が非常に長い場合は、try codeブロックでロックが10秒ごとに保持されているかどうかを確認できます。保持している場合は、ロック時間を延長して、ビジネスコードが実行されないようにします。 「それは有効期限です。
ここに写真の説明を挿入


テスト環境のセットアップ

Redisコマンドリスト

Redisパスワード
ここに写真の説明を挿入
pomを設定します

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.5.7</version>
        </dependency>

application.properties:

server.port=8090
# redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=888888
spring.redis.jedis.pool.max-active=500
spring.redis.jedis.pool.max-idle=1000
spring.redis.jedis.pool.max-wait=6000ms
spring.redis.jedis.pool.min-idle=4

Nginxロードバランシング:

 upstream redislock{
    
    
	server 127.0.0.1:8080 weight = 1;
	server 127.0.0.1:8090 weight = 1;
    }
    server {
    
    
        listen       80;
        server_name  localhost;
   		location / {
    
    
		root html;
		index index.html index.htm;
		proxy_pass http://redislock;
        }
    }

Jmeterストレステスト

ここに写真の説明を挿入
httpリクエスト
ここに写真の説明を挿入
の送信:送信アドレスの設定:
ここに写真の説明を挿入
0秒以内に200リクエストを送信し、処理後に200 * 3回送信し、合計200 * 4リクエスト:
ここに写真の説明を挿入
結果セット:
ここに写真の説明を挿入

テスト結果:
ここに写真の説明を挿入
ここに写真の説明を挿入
売られ過ぎの問題なし

おすすめ

転載: blog.csdn.net/weixin_41699562/article/details/105224835