0
点赞
收藏
分享

微信扫一扫

基于mysql的分布式锁

亿奇学 2021-09-28 阅读 39
码哥
  • 锁信息表sql
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` datetime(3)         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"  useGeneratedKeys="true" keyProperty="id">
        INSERT INTO lock_info(lock_key, expire_time)
        VALUES(#{lockKey}, #{expireTime})
    </insert>

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

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

    <select id="select" resultType="com.aliyun.ons.metadata.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>
            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);
        }
    }
}
举报

相关推荐

0 条评论