引擎本身的主键填充策略
首先可以先选一个service看看具体的数据库操作:
如图,具体的id设置主要是DataFillHandler接口的idFill方法。
Warm-Flow工作流引擎本身的主键填充主要依靠于DataFillHandler接口,这个接口主要定义了数据库操作时关于实体的id,新增操作和更新操作时字段的变更,分别可以负责实体的id,创建时间,更新时间的字段填充。
我们关于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中,如下图所示:
由图可知,我们的自定义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中,可以通过配置文件或者注解方式。