Skip to content
Merged

Dev #212

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ spring.jpa.showSql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=com.codingapi.example.dialect.HydDmDialect

# 开启 JDBC 批次插入,配合 SEQUENCE 主键(t_flow_record/t_flow_todo_record/t_flow_todo_marge/t_flow_sub_process_record)
# 将批量创建流程记录/待办/合并/子流程时的多次串行 INSERT 合并为批次往返,显著降低远程库耗时
spring.jpa.properties.hibernate.jdbc.batch_size=100
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true

spring.datasource.url=jdbc:dm://localhost:5236
spring.datasource.username=SYSDBA
spring.datasource.password=SYSDBA001
Expand Down
5 changes: 5 additions & 0 deletions flow-engine-example/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# 开启 JDBC 批次插入,配合 SEQUENCE 主键 + H2 序列,优化批量流程/待办/合并/子流程记录创建
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true

# Security
spring.main.allow-bean-definition-overriding=true
codingapi.security.jwt.enable=true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@
import com.codingapi.flow.repository.FlowTodoRecordRepository;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class FlowTodoRecordRepositoryMockImpl implements FlowTodoRecordRepository {

private final Map<Long, FlowTodoRecord> cache = new HashMap<>();
private final Map<String, FlowTodoRecord> cacheByMageKey = new HashMap<>();
private long nextId = 1;

// 查询计数器,供测试断言"按 key 逐条查询已被批量查询替代"(N+1 消除)
private int getByTodoKeyCalls;
private int findByKeysCalls;

@Override
public void save(FlowTodoRecord record) {
if (record.getId() > 0) {
Expand Down Expand Up @@ -41,9 +47,28 @@ public void delete(FlowTodoRecord margeRecord) {

@Override
public FlowTodoRecord getByTodoKey(String key) {
getByTodoKeyCalls++;
return cacheByMageKey.get(key);
}

@Override
public List<FlowTodoRecord> findByKeys(List<String> keys) {
findByKeysCalls++;
Set<String> keySet = new HashSet<>(keys);
return cacheByMageKey.entrySet().stream()
.filter(entry -> keySet.contains(entry.getKey()))
.map(Map.Entry::getValue)
.toList();
}

public int getGetByTodoKeyCalls() {
return getByTodoKeyCalls;
}

public int getFindByKeysCalls() {
return findByKeysCalls;
}

public List<FlowTodoRecord> findByOperatorId(long operatorId) {
return cache.values().stream().filter(record -> record.getCurrentOperatorId() == operatorId).toList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ public interface FlowTodoRecordRepository {

FlowTodoRecord getByTodoKey(String key);

/**
* 按多个待办合并 key 批量加载已存在的待办记录,用于替代循环内逐条 {@link #getByTodoKey(String)} 的 N+1 查询。
*
* @param keys 待办合并 key 列表
* @return 已存在的待办记录
*/
List<FlowTodoRecord> findByKeys(List<String> keys);

void delete(FlowTodoRecord margeRecord);

void save(FlowTodoRecord margeRecord);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@
import com.codingapi.flow.repository.FlowTodoRecordRepository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* 流程记录保存服务,负责保存流程记录和待办记录的合并关系
*/
class FlowRecordSaveService {

/**
* 批量加载已存在待办时单批查询的 key 上限,避免单个 IN 子句过大(SQL 限制)与结果集过大(内存)。
*/
private static final int TODO_KEY_BATCH_SIZE = 500;

private final List<FlowRecord> flowRecords;

private FlowTodoRecordRepository flowTodoRecordRepository;
Expand All @@ -41,12 +49,29 @@ public void registerRepositories(FlowTodoRecordRepository flowTodoRecordReposito


private void saveTodoMargeRecords() {
// 批量加载已存在的待办(而非逐条 getByTodoKey 的 N+1):
// 按分块大小分批 findByKeys,避免海量 key 拼在单个 IN 子句里导致 SQL/结果集过大(OOM 风险)。
List<String> todoKeys = flowRecords.stream()
.filter(FlowRecord::isTodo)
.map(FlowRecord::getTodoKey)
.filter(Objects::nonNull)
.distinct()
.toList();
Map<String, FlowTodoRecord> existedByKey = new HashMap<>();
for (int start = 0; start < todoKeys.size(); start += TODO_KEY_BATCH_SIZE) {
List<String> chunk = todoKeys.subList(start, Math.min(start + TODO_KEY_BATCH_SIZE, todoKeys.size()));
for (FlowTodoRecord existed : flowTodoRecordRepository.findByKeys(chunk)) {
existedByKey.put(existed.getTodoKey(), existed);
}
}

List<FlowTodoRecord> flowTodoRecords = new ArrayList<>();
for (FlowRecord flowRecord : flowRecords) {
if (flowRecord.isTodo()) {
FlowTodoRecord todoMargeRecord = flowTodoRecordRepository.getByTodoKey(flowRecord.getTodoKey());
FlowTodoRecord todoMargeRecord = existedByKey.get(flowRecord.getTodoKey());
if (todoMargeRecord == null) {
todoMargeRecord = new FlowTodoRecord(flowRecord);
existedByKey.put(flowRecord.getTodoKey(), todoMargeRecord);
} else {
todoMargeRecord.update(flowRecord);
if (flowRecord.isMergeable()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@
import com.codingapi.flow.record.FlowTodoRecord;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class FlowTodoRecordRepositoryImpl implements FlowTodoRecordRepository {

private final Map<Long, FlowTodoRecord> cache = new HashMap<>();
private final Map<String, FlowTodoRecord> cacheByMageKey = new HashMap<>();
private long nextId = 1;

// 查询计数器,供测试断言"按 key 逐条查询已被批量查询替代"(N+1 消除)
private int getByTodoKeyCalls;
private int findByKeysCalls;

@Override
public void save(FlowTodoRecord record) {
if (record.getId() > 0) {
Expand Down Expand Up @@ -40,9 +46,28 @@ public void delete(FlowTodoRecord margeRecord) {

@Override
public FlowTodoRecord getByTodoKey(String key) {
getByTodoKeyCalls++;
return cacheByMageKey.get(key);
}

@Override
public List<FlowTodoRecord> findByKeys(List<String> keys) {
findByKeysCalls++;
Set<String> keySet = new HashSet<>(keys);
return cacheByMageKey.entrySet().stream()
.filter(entry -> keySet.contains(entry.getKey()))
.map(Map.Entry::getValue)
.toList();
}

public int getGetByTodoKeyCalls() {
return getByTodoKeyCalls;
}

public int getFindByKeysCalls() {
return findByKeysCalls;
}

public List<FlowTodoRecord> findByOperatorId(long operatorId) {
return cache.values().stream().filter(record -> record.getCurrentOperatorId() == operatorId).toList();
}
Expand Down
Loading
Loading