zoukankan      html  css  js  c++  java
  • springboot使用Redisson实现分布式锁

    1.Redisson介绍

    Redisson是Redis官方推荐的Java版的Redis客户端。它提供的功能非常多,也非常强大,此处我们只用它的分布式锁功能。

    https://github.com/redisson/redisson

    2.实现分布式锁

     <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.15.0</version>
     </dependency>
    
    server:
      port: 8070
    spring:
      application:
        name: dkn-provider-store
      jackson:
        default-property-inclusion: non_null
        date-format: YYYY-MM-dd HH:mm:ss
        time-zone: GMT+8
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/dkn-provider-store?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: root
    
    logging:
      level:
        com.dkn: debug
        org.springframework.web: trace
    
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
    -- ----------------------------
    -- Table structure for store
    -- ----------------------------
    DROP TABLE IF EXISTS `store`;
    CREATE TABLE `store` (
      `id` int(11) NOT NULL COMMENT '商品id',
      `num` int(11) DEFAULT NULL COMMENT '库存数量',
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
    
    -- ----------------------------
    -- Records of store
    -- ----------------------------
    INSERT INTO `store` VALUES ('101', '100');
    
    @Configuration
    public class RedissonConfig {
        @Bean
        public RedissonClient redissonClient() {
            Config config = new Config();
            config.useSingleServer().setAddress("redis://127.0.0.1:6379");
            RedissonClient redisson = Redisson.create(config);
            return redisson;
        }
    
    }
    
    @Service
    public class StoreServiceImpl extends ServiceImpl<StoreMapper,Store> implements StoreService {
    
        @Autowired
        RedissonClient redissonClient;
    
        //没有任何锁
        @Override
        public void buy1(Integer id, Integer num) {
            Store store = this.getById(id);
    
            //模拟业务处理休息50毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            store.setNum(store.getNum()-1);
            this.updateById(store);
        }
    
        //同步
        @Override
        public synchronized void buy2(Integer id, Integer num) {
            Store store = this.getById(id);
    
            //模拟业务处理休息50毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            store.setNum(store.getNum()-1);
            this.updateById(store);
        }
    
        //分布式锁
        @Override
        public void buy3(Integer id, Integer num) {
            String lockKey = "buy:product:" + id;
            RLock lock = redissonClient.getLock(lockKey);
            try {
                boolean res = lock.tryLock(10, TimeUnit.SECONDS);
                if (res) {
                    Store store = this.getById(id);
    
                    //模拟业务处理休息50毫秒
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    store.setNum(store.getNum()-1);
                    this.updateById(store);
                }
            } catch (Exception ex) {
                log.error("获取所超时!", ex);
            } finally {
                lock.unlock();
            }
        }
    
    }
    
    @RestController
    @RequestMapping("/Store")
    public class StoreController {
    
    	@Autowired
    	private StoreService storeService;
    
    	//模拟购买商品 没有任何锁
    	@GetMapping("buy1")
    	public AjaxResult buy1(Integer id, Integer num){
    		storeService.buy1(id,num);
    		return AjaxResult.success();
    	}
    
    	//模拟购买商品 synchronized本地同步锁
    	@GetMapping("buy2")
    	public AjaxResult buy2(Integer id, Integer num){
    		storeService.buy2(id,num);
    		return AjaxResult.success();
    	}
    
    	//模拟购买商品 redisson分布锁
    	@GetMapping("buy3")
    	public AjaxResult buy3(Integer id, Integer num){
    		storeService.buy3(id,num);
    		return AjaxResult.success();
    	}
    	
    }
    

    3.测试

    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class StoreBuyTest {
    
        @Autowired
        RestTemplate restTemplate;
    
        //测试结果100个商品,库存只减少1个,应该减少50个
        @Test
        public void testBuy1(){
            //模拟50个用户同时购买一件物品
            ThreadPoolExecutor executor=new ThreadPoolExecutor(50,50,60, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
    
            for(int i=0;i<50;i++) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("===============================");
                        restTemplate.getForEntity("http://localhost:8070/Store/buy1?id=101&num=1", String.class);
                    }
                });
            }
    
            while (true){
                if(executor.getQueue().size()==0 && executor.getActiveCount()==0){
                    executor.shutdown();
                    break;
                }
    
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            System.out.println("end~");
        }
    
        //单个服务测试-->测试结果正确,测试结果100个商品,库存只减少50个
        @Test
        public void testBuy2_1(){
            //模拟50个用户同时购买一件物品
            ThreadPoolExecutor executor=new ThreadPoolExecutor(50,50,60, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
    
            for(int i=0;i<50;i++) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("===============================");
                        restTemplate.getForEntity("http://localhost:8070/Store/buy2?id=101&num=1", String.class);
                    }
                });
            }
    
            while (true){
                if(executor.getQueue().size()==0 && executor.getActiveCount()==0){
                    executor.shutdown();
                    break;
                }
    
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            System.out.println("end~");
        }
    
        //启动2个服务测试,端口分别是8070,8071-->测试结果不正常,测试结果100个商品,库存只减少26个,应该减少50个
        @Test
        public void testBuy2_2(){
            //模拟50个用户同时购买一件物品
            ThreadPoolExecutor executor=new ThreadPoolExecutor(50,50,60, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
    
            for(int i=0;i<50;i++) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("===============================");
                        if(RandomUtils.nextInt(0,100)<50){
                            restTemplate.getForEntity("http://localhost:8070/Store/buy2?id=101&num=1", String.class);
                        }else{
                            restTemplate.getForEntity("http://localhost:8071/Store/buy2?id=101&num=1", String.class);
                        }
                    }
                });
            }
    
            while (true){
                if(executor.getQueue().size()==0 && executor.getActiveCount()==0){
                    executor.shutdown();
                    break;
                }
    
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            System.out.println("end~");
        }
    
        //启动2个服务测试,端口分别是8070,8071-->测试结果正确,测试结果100个商品,库存减少50个
        @Test
        public void testBuy3(){
            //模拟50个用户同时购买一件物品
            ThreadPoolExecutor executor=new ThreadPoolExecutor(50,50,60, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
    
            for(int i=0;i<50;i++) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("===============================");
                        if(RandomUtils.nextInt(0,100)<50){
                            restTemplate.getForEntity("http://localhost:8070/Store/buy3?id=101&num=1", String.class);
                        }else{
                            restTemplate.getForEntity("http://localhost:8071/Store/buy3?id=101&num=1", String.class);
                        }
                    }
                });
            }
    
            while (true){
                if(executor.getQueue().size()==0 && executor.getActiveCount()==0){
                    executor.shutdown();
                    break;
                }
    
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            System.out.println("end~");
        }
    
    
    }
    
  • 相关阅读:
    Java [Leetcode 191]Number of 1 Bits
    Java [Leetcode 235]Lowest Common Ancestor of a Binary Search Tree
    Java [Leetcode 169]Majority Element
    Java [Leetcode 171]Excel Sheet Column Number
    Java [Leetcode 217]Contains Duplicate
    Java [Leetcode 242]Valid Anagram
    Java [Leetcode 100]Same Tree
    Java [Leetcode 258]Add Digits
    Java [Leetcode 104]Maximum Depth of Binary Tree
    D365 FO财务维度
  • 原文地址:https://www.cnblogs.com/daikainan/p/14422468.html
Copyright © 2011-2022 走看看