基于mysql的分布式锁

  • 锁信息表sql

避免时区问题,expire_time使用bigint存储时间戳

CREATE TABLE IF NOT EXISTS `lock_info`
(
    `id`          bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
    `lock_key`    varchar(128)        NOT NULL COMMENT '加锁的key',
    `expire_time` bigint unsigned     NOT NULL COMMENT '过期时间',
    `create_ts`   datetime(3)         NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
    `update_ts`   datetime(3)         NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_lock_key` (`lock_key`)
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT ='分布式锁信息表';

    <insert id="insert">
        INSERT INTO lock_info(lock_key, expire_time)
        VALUES(#{lockKey}, #{expireTime})
    </insert>

    <delete id="delete">
        delete from lock_info
        <where>
            and lock_key=#{lockKey}
            and expire_time=#{expireTime}
        </where>
        limit 1
    </delete>

    <update id="updateExpireTime">
        UPDATE lock_info
        <set>
            expire_time=#{newExpectTime},
        </set>
        <where>
            and lock_key=#{lockKey}
            and expire_time=#{oldExpectTime}
        </where>
    </update>

    <select id="select" resultType="cn.laifuzhi.template.model.PO.LockInfoPO">
        select id,
        lock_key as lockKey,
        expire_time as expireTime,
        create_ts as createTs,
        update_ts as updateTs
        from lock_info
        <where>
            and lock_key=#{lockKey}
        </where>
    </select>

@Slf4j
@Service
public class LockService {
    @Resource
    private LockInfoDao lockInfoDao;

    public Date tryLock(String lockKey, int expireSeconds) {
        Preconditions.checkArgument(StringUtils.isNotBlank(lockKey));
        try {
            Date now = new Date();
            Date newExpireTime = DateUtils.addSeconds(now, expireSeconds);
            LockInfoPO dbLockInfo = lockInfoDao.select(lockKey);
            if (dbLockInfo == null) {
                dbLockInfo = new LockInfoPO();
                dbLockInfo.setLockKey(lockKey);
                dbLockInfo.setExpireTime(newExpireTime);
                lockInfoDao.insert(dbLockInfo);
                return newExpireTime;
            }
            // 锁还未到过期时间,或者更新过期时间失败
            Date oldExpireTime = dbLockInfo.getExpireTime();
            if (now.before(oldExpireTime)
                    || lockInfoDao.updateExpireTime(lockKey, oldExpireTime, newExpireTime) <= 0) {
                return null;
            }
            log.info("tryLock key:{} expire:{}", lockKey, DateFormatUtils.format(newExpireTime, DATETIME_FORMAT));
            return newExpireTime;
        } catch (DuplicateKeyException e) {
            log.debug("tryLock duplicate key:{}", lockKey);
            return null;
        } catch (Exception e) {
            log.error("tryLock error key:{}", lockKey, e);
            return null;
        }
    }

    public void release(String lockKey, Date expectExpireTime) {
        Preconditions.checkArgument(StringUtils.isNotBlank(lockKey));
        try {
            boolean result = lockInfoDao.delete(lockKey, expectExpireTime) > 0;
            log.info("release key:{} expect:{} result:{}", lockKey, DateFormatUtils.format(expectExpireTime, DATETIME_FORMAT), result);
        } catch (Exception e) {
            log.error("release key error key:{} expect:{}", lockKey, DateFormatUtils.format(expectExpireTime, DATETIME_FORMAT), e);
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容