JBPM 7.44/Redhat PAM 7.10设置流程变量触发Hibernate“String or binary data would be truncated”异常的问题排查与解决咨询
首先咱们拆解下这个异常的根本原因:
JBPM在处理流程变量变更时,默认会把变量的旧值和新值记录到VariableInstanceLog表中。这个表的oldValue字段被定义为varchar(255),当你从第一阶段切换到第二阶段时,系统需要将第一阶段的Tasks变量(一个包含多个自定义任务的List)序列化后存入oldValue。如果序列化后的字符串长度超过255,SQL Server就会抛出「String or binary data would be truncated」的异常。
至于为什么迁移到嵌入式子流程后才触发错误?大概率是因为子流程的变量生命周期或变更触发逻辑和主流程不同——主流程中可能只是触发了日志警告(比如序列化超长时自动截断),但子流程的执行路径强制要求完整写入日志,直接触发了数据库层面的错误。
下面是针对性的解决方案,你可以根据业务需求选择:
1. 优化对象序列化,缩短存储长度
通过调整Hibernate/Jackson注解,减少Tasks集合序列化后的字符串体积,确保能塞进255字符的oldValue字段:
修改MyStage的tasks字段注解
添加Jackson注解忽略不必要的序列化字段,比如Hibernate的代理字段:
@javax.persistence.OneToMany(cascade = {javax.persistence.CascadeType.ALL}) @javax.persistence.JoinTable(name = "STAGE_TASKS_JOIN") @com.fasterxml.jackson.annotation.JsonProperty("tasks") @com.fasterxml.jackson.annotation.JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) // 忽略Hibernate代理冗余字段 @org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.FALSE) private java.util.List<com.me.MyTask> tasks;
优化MyTask类的序列化
在MyTask类上添加注解,只序列化非空字段,减少冗余内容:
@com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL) public class MyTask { // 你的类字段和方法 }
2. 禁用特定变量的变更日志
如果你不需要记录Tasks变量的变更历史,可以直接让JBPM跳过该变量的日志写入:
代码层面设置
在设置变量时,指定不记录日志:
// 第三个参数的VariableScope,第二个false表示禁用变量日志 kcontext.setVariable("Tasks", tasks, new org.kie.api.runtime.process.VariableScope(true, false));
流程定义层面设置
在BPMN文件的变量定义中,给Tasks变量添加log="false"属性:
<processVariables> <variable name="Tasks" type="java.util.List" log="false"/> </processVariables>
3. 修改数据库字段类型(如果允许)
如果有权限修改JBPM的数据库表,可以把VariableInstanceLog的oldValue字段从varchar(255)改为varchar(max)(SQL Server)或者text,彻底解决长度限制问题。不过这个操作需要谨慎,确保不会影响其他流程的日志记录。
4. 将Tasks设为临时变量(Transient)
如果Tasks变量只是流程运行时的临时数据,不需要持久化到JBPM的变量存储中,可以标记为transient:
代码层面设置
// VariableScope的第二个true表示标记为transient kcontext.setVariable("Tasks", tasks, new org.kie.api.runtime.process.VariableScope(true, true));
流程定义层面设置
在BPMN变量定义中添加transient="true":
<processVariables> <variable name="Tasks" type="java.util.List" transient="true"/> </processVariables>
这样JBPM不会把该变量存入数据库,自然也不会触发日志写入的截断异常。
内容的提问来源于stack exchange,提问作者Dr Dave

