当前位置: 代码网 > it编程>数据库>Nosql > 基于Mongodb分布式锁解决定时任务并发执行问题

基于Mongodb分布式锁解决定时任务并发执行问题

2024年05月18日 Nosql 我要评论
前言我们日常开发过程,会有一些定时任务的代码来统计一些系统运行数据,但是我们应用有需要部署多个实例,传统的通过配置文件来控制定时任务是否启动又太过繁琐,而且还经常出错,导致一些异常数据的产生网上有很多

前言

我们日常开发过程,会有一些定时任务的代码来统计一些系统运行数据,但是我们应用有需要部署多个实例,传统的通过配置文件来控制定时任务是否启动又太过繁琐,而且还经常出错,导致一些异常数据的产生

网上有很多分布式锁的实现方案,基于redis、zk、等有很多,但是我的就是一个用了mysql和mongo的小应用,不准备引入其他三方中间件来解决这个问题,撸一个简单的分布式锁来解决定时任务并发执行的问题,加锁操作的原子性和防死锁也都要支持,这里我使用mongodb写了allinone的工具类

all in one code

先上代码

@component
@slf4j
public class mongodblock {

    private static final int default_lock_timeout = 30;//锁的默认超时时间,单位秒

    private mongotemplate mongotemplate;
    private int locktimeout;

    public mongodblock(mongotemplate mongotemplate) {
        this.mongotemplate = mongotemplate;
        this.locktimeout = default_lock_timeout;
    }

    /**
     * 尝试获取分布式锁
     *
     * @param lockkey 锁的key
     * @return true:获取锁成功,false:获取锁失败
     */
    private boolean acquirelock(string lockkey) {
        lockdocument document = new lockdocument();
        document.setid(lockkey);
        document.setexpireat(instant.ofepochmilli(instant.now().toepochmilli() + locktimeout * 1000));
        try {
            mongotemplate.insert(document);
            return true;
        } catch (exception e) {

        }
        return false;
    }

    /**
     * 释放分布式锁
     *
     * @param lockkey 锁的key
     */
    private void releaselock(string lockkey) {
        query query = new query(criteria.where("key").is(lockkey));
        mongotemplate.remove(query, lockdocument.class);
        log.info("程序执行成功,释放分布式锁,lockkey:{}",lockkey);
    }

    /**
     * 分布式锁入口方法,参数lockname为锁的名称,lockkey为需要加锁的key,执行完成后自动释放锁
     *
     * @param lockkey
     * @param task
     * @param <t>
     * @throws exception
     */
    public <t> void executewithlock(string lockkey, itask<t> task) throws exception {
        boolean locked = acquirelock(lockkey);
        if (locked) {
            log.info("获取分布式锁成功,lockkey:{}",lockkey);
            try {
                task.execute();
            } finally {
                releaselock(lockkey);
            }
        } else {
            log.warn("获取分布式锁失败,lockkey:{}", lockkey);
            throw new appexception("获取分布式锁失败!");
        }
    }

    @data
    @document(collection = "lock_collection")
    static class lockdocument {
        @id
        private string id;
        @indexed(expireafterseconds = default_lock_timeout)
        private instant expireat;
    }

    @functionalinterface
    public interface itask<t> {
        t execute() throws exception;
    }
}

调用示例

    @resource
    mongodblock mongodblock;

    mongodblock.executewithlock("key", () -> {
        // do some thing
        return null;
    });

原理

  • 使用key作为主键,利用mongodb的insert原子性保障lockdocument不会重复插入
  • lockdocument中expireat字段利用的mongodb索引过期机制,解决死锁问题,这里设置超时时间是30秒,并在执行完成之后会主动释放锁

到此这篇关于基于mongodb分布式锁简单实现,解决定时任务并发执行问题的文章就介绍到这了,更多相关mongodb分布式锁内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com