'# Springboot整合activiti5,达梦数据库,mybatis中间件
一、背景与问题
在企业级应用开发中,流程引擎的引入往往伴随着复杂的业务逻辑和数据持久化需求。Activiti5作为成熟的工作流引擎,其核心特性是支持BPMN2标准流程定义,通过流程实例的生命周期管理实现业务流程自动化。在国产化替代背景下,达梦数据库作为国产关系型数据库的代表,其兼容性、安全性需求与传统MySQL存在显著差异。MyBatis作为ORM框架,需要与Spring Boot整合实现数据持久化。
典型技术挑战包括:
- 达梦数据库的JDBC驱动兼容性
- Activiti5的流程引擎配置与达梦数据库的适配
- MyBatis与Activiti的数据库表结构映射
- 流程实例状态的持久化与并发控制
二、基本原理
1. Activiti5核心架构
Activiti5基于流程定义(BPMN2)构建流程引擎,其核心组件包括:
- 流程引擎(ProcessEngine):负责流程实例的创建、执行、挂起等
- 数据库支持:通过JobRepository、HistoryLevel等配置持久化流程状态
- 任务管理:TaskService提供任务创建、分配、完成等API
2. 达梦数据库特性
达梦数据库支持标准SQL语法,但存在以下差异:
- 特定函数:如
DMDBMS_JOB等达梦特有的作业管理函数 - 字符集:需要显式配置字符集(如
NLS_CHARACTERSET=AL32UTF8) - 索引优化:对B-Tree索引的优化策略不同于MySQL
3. MyBatis整合机制
MyBatis通过以下方式与Spring Boot整合:
- 使用
@Mapper注解定义DAO接口 - 配置
SqlSessionFactory绑定数据源 - 通过
@Select等注解实现数据库查询
三、环境准备
1. 依赖配置
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>5.22.0</version>
</dependency>
<dependency>
<groupId>com.dameng</groupId>
<artifactId>dm-jdbc</artifactId>
<version>19.2.2.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>2. 达梦数据库配置
# application.yml
spring:
datasource:
url: jdbc:dm://127.0.0.1:5236/activiti?characterEncoding=UTF-8
username: sysdba
password: 123456
driver-class-name: dm.jdbc.driver.DmDriver四、核心实现
1. 流程引擎配置
// ActivitiConfig.java
@Configuration
public class ActivitiConfig {
@Bean
public ProcessEngine processEngine(DataSource dataSource) {
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
configuration.setDataSource(dataSource);
configuration.setJdbcUrl("jdbc:dm://127.0.0.1:5236/activiti");
configuration.setJdbcDriver("dm.jdbc.driver.DmDriver");
configuration.setJdbcUsername("sysdba");
configuration.setJdbcPassword("123456");
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
return configuration.buildProcessEngine();
}
}2. MyBatis实体映射
// User.java
@Entity
@Table(name = "ACT_ID_INFO")
public class User {
@Id
@Column(name = "ID_")
private String id;
@Column(name = "NAME_")
private String name;
// getters and setters
}// UserMapper.java
@Mapper
public interface UserMapper {
@Select("SELECT * FROM ACT_ID_INFO WHERE ID_ = #{id}")
User selectById(String id);
}3. 流程实例管理
// ProcessService.java
@Service
public class ProcessService {
@Autowired
private ProcessEngine processEngine;
@Autowired
private UserMapper userMapper;
public void startProcess(String userId) {
RepositoryService repositoryService = processEngine.getRepositoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
// 创建流程定义
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/loan.bpmn20.xml")
.name("贷款审批流程")
.deploy();
// 启动流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("loanProcess",
Collections.singletonMap("userId", userId));
// 获取当前任务
Task task = runtimeService.createTaskQuery()
.processInstanceId(processInstance.getId())
.singleResult();
// 关联用户
taskService.setOwner(task.getId(), userMapper.selectById(userId).getName());
}
}五、完整案例
1. 审批流程案例
业务场景:贷款审批流程需要经过部门经理、风控专员、审批委员会三级审核
流程定义文件(loan.bpmn20.xml):
<process id="loanProcess" name="贷款审批流程">
<startEvent id="startEvent" />
<sequenceFlow id="flow1" sourceRef="startEvent" targetRef="managerTask" />
<userTask id="managerTask" name="部门经理审批" />
<sequenceFlow id="flow2" sourceRef="managerTask" targetRef="riskTask" />
<userTask id="riskTask" name="风控专员审核" />
<sequenceFlow id="flow3" sourceRef="riskTask" targetRef="committeeTask" />
<userTask id="committeeTask" name="审批委员会决议" />
<sequenceFlow id="flow4" sourceRef="committeeTask" targetRef="endEvent" />
<endEvent id="endEvent" />
</process>2. 业务代码实现
// LoanService.java
@Service
public class LoanService {
@Autowired
private ProcessEngine processEngine;
@Autowired
private UserMapper userMapper;
public void approveLoan(String userId, String taskId) {
TaskService taskService = processEngine.getTaskService();
HistoryService historyService = processEngine.getHistoryService();
// 完成任务
taskService.complete(taskId, Collections.singletonMap("approved", "true"));
// 获取流程实例
ProcessInstance processInstance = historyService.createProcessInstanceQuery()
.processInstanceId(taskService.getTask(taskId).getProcessInstanceId())
.singleResult();
// 输出流程状态
System.out.println("流程状态: " + processInstance.getState());
}
}六、源码解析
1. Activiti流程引擎启动流程
// ProcessEngineConfiguration.java
public class ProcessEngineConfiguration {
public ProcessEngine buildProcessEngine() {
// 初始化数据库连接
dataSource = createDataSource();
// 创建流程引擎
processEngine = new ProcessEngine();
// 初始化数据库表结构
initializeDatabaseSchema();
return processEngine;
}
private void initializeDatabaseSchema() {
// 执行DDL语句创建Activiti需要的表
executeDDLStatements();
}
}2. MyBatis与Activiti的交互
// Activiti数据库表结构
CREATE TABLE ACT_ID_INFO (
ID_ VARCHAR(255) PRIMARY KEY,
NAME_ VARCHAR(255),
PARENT_ID_ VARCHAR(255),
REV_ INT
);
CREATE TABLE ACT_RU_TASK (
ID_ VARCHAR(255) PRIMARY KEY,
NAME_ VARCHAR(255),
PARENT_TASK_ID_ VARCHAR(255),
PROC_INST_ID_ VARCHAR(255),
PROC_DEFINITION_ID_ VARCHAR(255)
);七、进阶使用
1. 自定义流程监听器
// CustomTaskListener.java
public class CustomTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
// 自定义任务处理逻辑
System.out.println("任务 " + delegateTask.getId() + " 被处理");
}
}2. 流程变量管理
// ProcessVariableService.java
@Service
public class ProcessVariableService {
@Autowired
private RuntimeService runtimeService;
public void setVariables(String processInstanceId, Map<String, Object> variables) {
runtimeService.setVariables(processInstanceId, variables);
}
}3. 多租户支持
// TenantConfig.java
@Configuration
public class TenantConfig {
@Bean
public TenantProvider tenantProvider() {
return new CustomTenantProvider();
}
static class CustomTenantProvider implements TenantProvider {
@Override
public String getTenantId() {
// 从请求头中获取租户ID
return "tenant_1";
}
}
}八、性能与工程实践
1. 性能优化策略
| 优化点 | 方法 | 说明 |
|---|---|---|
| 索引优化 | 在ACT_RU_TASK表添加索引 | 为PROCESS_INSTANCE_ID_字段添加索引提升查询性能 |
| 缓存机制 | 使用Redis缓存流程定义 | 减少数据库访问频率 |
| 并发控制 | 配置流程引擎的并发策略 | 避免过多并发任务导致资源争用 |
2. 安全风险防范
- 使用PreparedStatement防止SQL注入
- 配置Spring Security进行流程访问控制
- 对Activiti的数据库表进行权限隔离
3. 异常处理机制
// ExceptionHandler.java
@ControllerAdvice
public class ExceptionHandler {
@ExceptionHandler(ProcessEngineException.class)
public ResponseEntity<String> handleProcessEngineException(ProcessEngineException ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
}
}九、常见问题与踩坑
1. 达梦驱动兼容性问题
问题:使用达梦驱动时出现"Invalid connection string"错误
解决方法:
- 确认驱动版本与达梦数据库版本匹配
- 检查JDBC URL格式是否正确(需包含字符集参数)
- 在application.yml中显式配置连接参数
spring:
datasource:
url: jdbc:dm://127.0.0.1:5236/activiti?characterEncoding=UTF-82. Activiti表结构不匹配
问题:初始化数据库时出现"Table not found"错误
解决方法:
- 确认达梦数据库的字符集设置
- 手动创建Activiti需要的表结构
- 配置
databaseSchemaUpdate为true
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);3. 流程实例状态不一致
问题:流程实例在完成任务后状态未更新
解决方法:
- 检查任务完成时是否调用了
taskService.complete()方法 - 验证流程定义文件是否正确
- 检查流程引擎配置是否启用历史记录
十、最佳实践
- 版本控制:使用Git管理流程定义文件,确保版本可追溯
- 监控机制:集成Prometheus监控Activiti运行状态
- 安全配置:对敏感流程定义文件进行加密存储
- 日志管理:使用ELK stack进行流程日志分析
- 灾备方案:定期备份Activiti的数据库表结构
十一、总结
Spring Boot整合Activiti5、达梦数据库和MyBatis的实践需要深入理解各技术组件的协同工作机制。在实际开发中,需要特别注意达梦数据库的特殊配置要求,合理设计流程定义文件,确保流程实例的持久化与状态管理。通过合理的性能优化策略和安全防护措施,可以构建稳定可靠的业务流程系统。这种技术方案适用于需要复杂流程管理的企业级应用,但需要避免在轻量级业务场景中过度使用,以免造成系统复杂度增加。