Redis分布式锁(二)-使用Redisson模拟Redis单实例下的分布式锁处理业务数据

使用Redisson模拟Redis单实例下的分布式锁处理业务数据

文字图片描述

模拟描述

多个进程同时处理业务数据,每处理一条业务数据,把业务数据中被处理的次数累加1,初始处理次数为0,SQL为update loan set deal_instance = #{deal_instance}, deal_count = deal_count + 1 where id = #{id}。处理结束后,看是否存在被处理次数大于1的情况发生,若存在则表明业务数据被重复处理了,分布式锁不起作用。

模拟情况说明
  1. MySQL数据库中有50000条业务数据需要处理

  2. 部署了4个进程(模拟生产上的4个集群实例)

在这里插入图片描述

预期结果
  1. 业务数据无重复处理的情况发生
结果说明

开始时间:01:50:17.400

结束时间:02:03:13.601

TPS:50000/(02:03:13-01:50:17之间的秒数)=64

无重复处理情况发生

在这里插入图片描述

代码

MainClass
package com.creasy.redis;

import com.creasy.dao.ILoanDao;
import com.creasy.pojo.Loan;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author laicreasy
 */
public class MainLockTest {

    private static final Logger log = LoggerFactory.getLogger(MainLockTest.class);

    private static final long LEASE_TIME = 10;

    public static void main(String[] args) throws InterruptedException, IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//Redis配置
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        RedissonClient redisson = Redisson.create(config);
        RLock lock = redisson.getLock("myLock");

        while (true){
//获取锁
            boolean res = lock.tryLock(new Random().nextInt(10), LEASE_TIME, TimeUnit.SECONDS);
            if (res) {
                //模拟获得锁之后处理业务数据
                try {
                    log.info("Get lock");
                    SqlSession session = sqlSessionFactory.openSession();
                    ILoanDao mapper = session.getMapper(ILoanDao.class);
                    Loan loan = mapper.queryLoanWithoutDeal();
                    if( loan == null ) {
                        break;
                    }
                    loan.setDeal_instance("PID:" + ManagementFactory.getRuntimeMXBean().getPid());
                    mapper.updateLoan(loan);
                    session.commit();
                    session.close();
                } finally {
                    log.info("Release lock");
                    try{
//释放锁
                        lock.unlock();
                    } catch (Exception e){
                        log.error(e.getMessage(), e);
                    }
                }
            }
//            TimeUnit.MILLISECONDS.sleep(new Random().nextInt(10));
        }
        redisson.shutdown();
    }

}

SQL
-- 建表语句
DROP TABLE IF EXISTS `loan`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `loan` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `deal_instance` varchar(40) DEFAULT NULL,
  `deal_count` int(10) DEFAULT '0',
  `loan_amount` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=50003 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping routines for database 'usersys'
--
/*!50003 DROP PROCEDURE IF EXISTS `insert_loan_loop` */;
/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client  = utf8mb4 */ ;
/*!50003 SET character_set_results = utf8mb4 */ ;
/*!50003 SET collation_connection  = utf8mb4_0900_ai_ci */ ;
/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
/*!50003 SET sql_mode              = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION' */ ;
-- 插入50000条数据
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `insert_loan_loop`()
BEGIN
 DECLARE x  INT;

 SET x = 1;

 WHILE x  <= 50000 DO
 insert into loan(loan_amount) values (x);
 SET  x = x + 1; 
 END WHILE;

 END ;;
DELIMITER ;

具体代码可看:github

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redisson是一个Redis的Java客户端,它提供了分布式锁的实现。在Redisson中,分布式锁使用Redis的命令实现,具有高性能、可重入、可自动续期等特点。最优实现如下: 1. 引入Redisson的依赖包: ``` <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.16.1</version> </dependency> ``` 2. 创建Redisson实例: ``` Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); ``` 3. 获取分布式锁: ``` RLock lock = redisson.getLock("myLock"); lock.lock(); try { //执行业务逻辑 } finally { lock.unlock(); } ``` 4. 可重入锁: ``` RLock lock = redisson.getLock("myLock"); lock.lock(); try { lock.lock(); try { //执行业务逻辑 } finally { lock.unlock(); } } finally { lock.unlock(); } ``` 5. 自动续期锁: ``` RLock lock = redisson.getLock("myLock"); lock.lock(10, TimeUnit.SECONDS); try { //执行业务逻辑 } finally { lock.unlock(); } ``` 6. 使用异步锁: ``` RLock lock = redisson.getLock("myLock"); RFuture<Boolean> future = lock.tryLockAsync(10, TimeUnit.SECONDS); try { Boolean res = future.get(); if (res) { //执行业务逻辑 } } finally { lock.unlock(); } ``` 7. 监听锁: ``` RLock lock = redisson.getLock("myLock"); RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch"); latch.trySetCount(1); lock.lock(); try { latch.await(); //执行业务逻辑 } finally { lock.unlock(); } ``` 8. 公平锁: ``` RLock lock = redisson.getFairLock("myFairLock"); lock.lock(); try { //执行业务逻辑 } finally { lock.unlock(); } ``` 通过以上最优实现,可以很方便地使用Redisson实现Redis分布式锁操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值