Warm-Flow工作流引擎数据库主键自增策略实现

841 阅读3分钟

引擎本身的主键填充策略

首先可以先选一个service看看具体的数据库操作:

image.png 如图,具体的id设置主要是DataFillHandler接口的idFill方法。

Warm-Flow工作流引擎本身的主键填充主要依靠于DataFillHandler接口,这个接口主要定义了数据库操作时关于实体的id,新增操作和更新操作时字段的变更,分别可以负责实体的id,创建时间,更新时间的字段填充。

image.png

我们关于ID字段的填充实现主要依赖于该接口的默认实现:DefaultDataFillHandler,其中关于id填充策略如下:

@Override
public void idFill(Object object) {
    RootEntity entity = (RootEntity) object;
    if (ObjectUtil.isNotNull(entity)) {
        if (Objects.isNull(entity.getId())) {
            entity.setId(IdUtils.nextId());
        }
    }
}

因此Id的获取是基于IdUtils,这是一个Id工具类,其内部的实现主要是基于定制的SnowFlake实现,可以根据nextId()方法来获得一个全局唯一Id。

关于数据填充handler,Warm-Flow支持自定义实现策略

前面提到了关于实体类的id填充主要是依赖于DataFillHandler接口,而该接口的实例化位于FlowFactory中,如下图所示:

image.png

由图可知,我们的自定义DataFillHandler的实例化有两种方式,第一种是在配置文件中设置类路径,第二种则是通过@Bean/@Component注入。如果没有设置自定义的数据填充器的话就会采用默认的实现,就是上文提到的雪花算法。

所以,实现主键自增策略就可以依靠自定义的数据填充器自定义的工具类

自定义的数据填充器

主要就是实现DataFillHandler,然后采用自己的工具类实现:

public class CustomDataFillHandler implements DataFillHandler {

    @Override
    public void idFill(Object object) {
        RootEntity entity = (RootEntity) object;
        if (ObjectUtil.isNotNull(entity)) {
            if (Objects.isNull(entity.getId())) {
                entity.setId(AutoIncrementIdGenerate.nextId(object));
            }
        }
    }

    @Override
    public void insertFill(Object object) {
        RootEntity entity = (RootEntity) object;
        if (ObjectUtil.isNotNull(entity)) {
            Date date = ObjectUtil.isNotNull(entity.getCreateTime())
                    ? entity.getCreateTime() : new Date();
            entity.setCreateTime(date);
            entity.setUpdateTime(date);
        }
    }

    @Override
    public void updateFill(Object object) {
        RootEntity entity = (RootEntity) object;
        if (ObjectUtil.isNotNull(entity)) {
            entity.setUpdateTime(new Date());
        }
    }
}

自定义主键自增工具类实现

工具类的实现除了满足需求之外,还应该保证线程安全,并拥有宕机恢复的能力,因此,基于主流的分布式Id生成方案,示例采用NOSQL数据库redis来实现记录的保存和获取,具体的代码如下:

public class AutoIncrementIdGenerate {

    private static final RedissonClient redissonClient;

    static {
        Config config = new Config();
        // 配置单个 Redis 服务器
        config.useSingleServer()
                .setAddress("")
                .setPassword("");
        // 创建 Redisson 客户端
        redissonClient = Redisson.create(config);
    }

    private static boolean initFlag = false;

    private static final String WARMFLOW_DEFINITION = "definition_id";
    private static final String WARMFLOW_HISTASK = "hisTask_id";
    private static final String WARMFLOW_INSTANCE = "instance_id";
    private static final String WARMFLOW_NODE = "node_id";
    private static final String WARMFLOW_SKIP = "skip_id";
    private static final String WARMFLOW_TASK = "task_id";
    private static final String WARMFLOW_USER = "user_id";

    public static void init() {
        RAtomicLong definition = redissonClient.getAtomicLong(WARMFLOW_DEFINITION);
        RAtomicLong hisTask = redissonClient.getAtomicLong(WARMFLOW_HISTASK);
        RAtomicLong instance = redissonClient.getAtomicLong(WARMFLOW_INSTANCE);
        RAtomicLong node = redissonClient.getAtomicLong(WARMFLOW_NODE);
        RAtomicLong skip = redissonClient.getAtomicLong(WARMFLOW_SKIP);
        RAtomicLong task = redissonClient.getAtomicLong(WARMFLOW_TASK);
        RAtomicLong user = redissonClient.getAtomicLong(WARMFLOW_USER);
        if (definition.get() == 0) {
            definition.set(0L);
        }
        if (hisTask.get() == 0) {
            definition.set(0L);
        }
        if (instance.get() == 0) {
            instance.set(0L);
        }
        if (node.get() == 0) {
            node.set(0L);
        }
        if (skip.get() == 0) {
            skip.set(0L);
        }
        if (task.get() == 0) {
            task.set(0L);
        }
        if (user.get() == 0) {
            user.set(0L);
        }
        initFlag = true;
    }

    public static Long nextId(Object object) {
        if (!initFlag) {
            init();
        }
        Long res;
        if (object instanceof Definition) {
            RAtomicLong definition = redissonClient.getAtomicLong(WARMFLOW_DEFINITION);
            res = definition.incrementAndGet();
        } else if (object instanceof HisTask) {
            RAtomicLong hisTask = redissonClient.getAtomicLong(WARMFLOW_HISTASK);
            res = hisTask.incrementAndGet();
        } else if (object instanceof Instance) {
            RAtomicLong instance = redissonClient.getAtomicLong(WARMFLOW_INSTANCE);
            res = instance.incrementAndGet();
        } else if (object instanceof Node) {
            RAtomicLong node = redissonClient.getAtomicLong(WARMFLOW_NODE);
            res = node.incrementAndGet();
        } else if (object instanceof Skip) {
            RAtomicLong skip = redissonClient.getAtomicLong(WARMFLOW_SKIP);
            res = skip.incrementAndGet();
        } else if (object instanceof Task) {
            RAtomicLong task = redissonClient.getAtomicLong(WARMFLOW_TASK);
            res = task.incrementAndGet();
        } else {
            RAtomicLong user = redissonClient.getAtomicLong(WARMFLOW_USER);
            res = user.incrementAndGet();
        }
        return res;
    }

}

总结

实现主键自增策略,主要以下步骤:1.自定义工具类实现自增逻辑;2.实现DataFillHandler接口,在接口内调用自定义的工具类来完成对Id的填充;3.将自定义的DataFillHandler实现注册到Spring中,可以通过配置文件或者注解方式。