redission扣库存demo

        在分布式场景中,要实现锁如果仅仅通过Synchronized关键字是不行的,因为Synchronized只是在此java进程中进行了上锁。要想实现分布式锁即可采用redission。本文采用nginx反向代理+redission实现扣库存demo。

引入依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.redisson</groupId>
			<artifactId>redisson</artifactId>
			<version>3.10.6</version>
		</dependency>
@Configuration
public class RedisConfig {

    @Bean
    public RedissonClient getRedisClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("123456");
        return Redisson.create(config);
    }

}
@RestController
public class RedissionController {

    @Autowired
    RedissonClient redissonClient;
    
    @GetMapping(value = "/getLock")
    public String getLock() {
        String lockKey = "lock";
        String key = "shopKey";
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock();
            RBucket<String> bucket = redissonClient.getBucket(key);
            int stock = Integer.parseInt(bucket.get());
            if (stock > 0) {
                int realStock = stock - 1;
                bucket.set(String.valueOf(realStock));
                System.out.println("出售成功,剩余:"+ realStock);
                return "success";
            }else{
                System.out.println("剩余库存不足");
                return "fail";
            }
        } finally {
            lock.unlock();
        }

    }

}

操作redis客户端有许多种(jedis,lettuce,redission对比),官方推荐的java客户端如jedis,springboot2.0默认采用的lettuce,以及redission,这里就直接采用redission。而采用redission需要注意的是bucket概念,RBucket对象是一种通用对象桶可以用来存放任类型的对象,它底层是默认采用 FstCodec进行序列化存储,因为需要提前往redis里面录入50库存,如果直接set shopKey 50 ,当调用redissonClient.getBucket(key),会出下面的异常,因为序列化前后的类型不一致。

2019-05-15 13:39:59.973 [redisson-netty-2-3] ERROR o.r.c.h.CommandDecoder [decodeCommand:203]     - Unable to decode data. channel: [id: 0x477c5ced, L:/192.168.4.94:57423 - R:10.10.10.43/10.10.10.43:6379], reply: ReplayingDecoderByteBuf(ridx=102, widx=102), command: (GET), params: [Geek:xxxxx:xxxx]
java.io.IOException: java.lang.NullPointerException
    at org.nustaq.serialization.FSTObjectInput.readObject(FSTObjectInput.java:247)
    at org.redisson.codec.FstCodec$1.decode(FstCodec.java:228)
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:368)
    at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:200)
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:140)
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:115)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:502)
    at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:278)

有两种解决方式

1.一种是直接插入序列化后的结果 那么调用redissonClient.getBucket(key)反序列化类型也是一致的
set shopKey "\xfc\x0250"


​​​​​​​2.一种是设置bucket序列化方式然后进行set
​​​​​​​redissonClient.getBucket(key, new StringCodec());
​​​​​​​set shopKey 50

nginx配置 大部分采用默认配置即可,需要修改的地方已经通过 # //标示出来,配置完成后使用该配置文件启动一下即可。  

启动命令 -c 表示启动时使用下面的配置文件,也可以在启动前采用-t命令测试是否配置成功,如果配置成功会显示xx.conf test is successful,然后再启动。

/usr/local/Cellar/nginx/1.21.1/bin/nginx  -c /usr/local/Cellar/nginx/1.21.1/.bottle/etc/nginx/nginx.conf

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    
    # // 实现一个负载均衡 8081,8082端口依次访问
    upstream redisLock{
     server 10.254.2.27:8081 weight=1; #ipV4,通过ipconfig命令查看
     server 10.254.2.27:8082 weight=1;
    }
 
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
           # // 转发到上面配置的upstream
            proxy_pass   http://redisLock;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    include servers/*;
}

然后idea分别启动8081,8082两个端口,然后访问http://127.0.0.1/getLock即可,这里可以使用jmeter和postman模拟并发请求。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值