Mysql可重入的分布式锁

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xin.mapper.LocksMapper">
    <update id="updateLockVersion">
        update t_lock set version=version+1,timeout=0,request_id=#{requestId},lock_count=#{lockCount}  where lock_key=#{lockKey} and version =#{version}
    </update>


    <select id="getLock" resultType="com.xin.entity.LocksEntity">
        select * from t_lock where lock_key=#{lockKey} for update
    </select>


</mapper>

/*

package com.xin.utils;

import com.xin.entity.LocksEntity;
import com.xin.service.LocksService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.UUID;

@Component
public class LockVersion {

    @Resource
    private LocksService locksService;

    private ThreadLocal<String> threadLocal = new ThreadLocal<>();
    @Resource
    private RedisTemplate redisTemplate;

    /**
     *
     * @param lockKey 锁的标识
     * @param timeOut 获取锁的超时时间
     * @param possessTime 持有锁的时间
     * @return
     */
    public boolean getLock(String lockKey,Long timeOut,Long possessTime) throws InterruptedException {
        String requireKey = this.getRequireKey();
        Long startTime = System.currentTimeMillis();
        while (true) {
            //获取锁对象
            LocksEntity lock = this.locksService.getLock(lockKey);
            //创建一个锁对象,并且自己尝试去获取该锁对象
            if (lock==null){
                if (this.redisTemplate.boundValueOps(lockKey).setIfAbsent(lockKey)){
                    LocksEntity locksEntity  = new LocksEntity(lockKey,"",0,0L,0);
                    this.locksService.add(locksEntity);
                }
            }
            else {
                //说明当前锁没有被其他线程持有
                if (lock.getRequestId()==null||lock.getRequestId().equals("")){
                    System.out.println("当前线程没有被其他线程持有");
                    lock.setRequestId(requireKey);
                    lock.setTimeout(possessTime+System.currentTimeMillis());
                    lock.setLockCount(lock.getLockCount()+1);
                    //使用数据库乐观锁
                    Integer integer = this.locksService.updateLockVersion(lock);
                    if (integer>=1) return true;
                    else Thread.sleep(100);
                }
                //说明当前锁被自己持有
                else if (lock.getRequestId()!=null&&lock.getRequestId().equals(requireKey)){
                    System.out.println("进行锁重入");
                    //进行一个锁的重入
                    lock.setLockCount(lock.getLockCount()+1);
                    //使用数据库乐观锁
                    Integer integer = this.locksService.updateLockVersion(lock);
                    if (integer>=1) return true;
                    else Thread.sleep(100);
                }
                //说明当前锁不是被自己持有,被其他线程持有
                else {
                    //判断其他线程持有锁的时间是否超时
                    if (lock.getTimeout()>System.currentTimeMillis()){
                        System.out.println("其他线程持有锁超时");
                        //重置锁
                        lock.setLockCount(0);
                        lock.setVersion(0);
                        lock.setTimeout(0L);
                        lock.setRequestId("");
                        this.locksService.updateById(lock);
                    }
                    //判断自己获取是否已经超时
                    if (timeOut+startTime>System.currentTimeMillis()){
                        System.out.println("自己获取锁超时");
                        return false;
                    }
                }
            }
        }
    }

    /**
     * 释放锁
     * @param lockKey 
     * @return
     */
    public boolean unLock(String lockKey){
        String requireKey = getRequireKey();
        LocksEntity lock = this.locksService.getLock(lockKey);
        //判断自己是否锁的持有者
        if (requireKey.equals(lock.getRequestId())){
            lock.setVersion(0);
            lock.setTimeout(0L);
            lock.setLockCount(0);
            lock.setRequestId("");
            boolean b = this.locksService.updateById(lock);
            if (b) return true;
        }
        return false;
    }

    /**
     * 获取请求key
     * @return
     */
    public String  getRequireKey(){
        String key = threadLocal.get();
        if (key==null){
            key= UUID.randomUUID().toString();
            threadLocal.set(key);
        }
        return key;
    }
}


 Navicat Premium Data Transfer

 Source Server         : Product
 Source Server Type    : MySQL
 Source Server Version : 80022
 Source Host           : localhost:3306
 Source Schema         : javacode2018

 Target Server Type    : MySQL
 Target Server Version : 80022
 File Encoding         : 65001

 Date: 02/12/2023 15:13:49
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_lock
-- ----------------------------
DROP TABLE IF EXISTS `t_lock`;
CREATE TABLE `t_lock`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `lock_key` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '锁唯一标志',
  `request_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '用来标识请求对象的',
  `lock_count` int(0) NOT NULL DEFAULT 0 COMMENT '当前上锁次数',
  `timeout` bigint(0) NOT NULL DEFAULT 0 COMMENT '锁超时时间',
  `version` int(0) NOT NULL DEFAULT 0 COMMENT '版本号,每次更新+1',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1729784763572424705 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '锁信息表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值