4.0 KiB
4.0 KiB
关于数据库审计字段(create_by, create_time等)的处理方案
问题描述
在使用OpenHIS系统时,可能会遇到如下错误:
org.postgresql.util.PSQLException: ERROR: null value in column "create_by" of relation "adm_practitioner" violates not-null constraint
问题分析
- 数据库表中的审计字段(如create_by, create_time)设置了NOT NULL约束
- 应用程序层面使用了MyBatis-Plus的自动填充功能来设置这些字段
- 当自动填充机制失效时,就会出现违反非空约束的错误
解决方案
方案一:修复自动填充机制(推荐)
系统已经实现了自动填充机制,位于 MybastisColumnsHandler.java:
// 设置数据新增时候的,字段自动赋值规则
@Override
public void insertFill(MetaObject metaObject) {
// 同时填充驼峰和下划线命名的字段,以兼容不同的配置
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "create_time", Date.class, new Date());
String username = "system";
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
username = loginUser.getUsername();
}
} catch (Exception ignored) {
}
// 使用 fillStrategy 确保即使字段为 null 也会被填充
this.strictInsertFill(metaObject, "createBy", String.class, username);
this.strictInsertFill(metaObject, "create_by", String.class, username);
// 如果 strictInsertFill 没有生效,使用 setFieldValByName 强制设置
if (metaObject.hasGetter("createBy") && metaObject.getValue("createBy") == null) {
this.setFieldValByName("createBy", username, metaObject);
}
if (metaObject.hasGetter("create_by") && metaObject.getValue("create_by") == null) {
this.setFieldValByName("create_by", username, metaObject);
}
...
}
确保所有实体类都继承自 HisBaseEntity 或 BaseEntity,这样就能自动获得审计字段。
方案二:移除数据库约束(谨慎使用)
如果确实需要允许审计字段为NULL,可以移除数据库约束:
-- 移除 adm_practitioner 表中 create_by 列的 NOT NULL 约束
ALTER TABLE "public"."adm_practitioner"
ALTER COLUMN "create_by" DROP NOT NULL;
-- 同样处理 create_time 列(如果需要)
ALTER TABLE "public"."adm_practitioner"
ALTER COLUMN "create_time" DROP NOT NULL;
方案三:批量修复所有表的约束
如果多个表都存在这个问题,可以使用以下脚本:
-- 为所有表的审计字段移除NOT NULL约束
-- 注意:执行前请备份数据库!
-- 1. 检查所有包含审计字段的表
SELECT
table_name,
column_name,
is_nullable
FROM
information_schema.columns
WHERE
column_name IN ('create_by', 'create_time', 'update_by', 'update_time')
AND table_schema = 'public'
AND is_nullable = 'NO'; -- NO 表示 NOT NULL 约束
-- 2. 根据需要移除特定表的约束
-- 示例:移除多个表的create_by约束
ALTER TABLE "public"."adm_practitioner" ALTER COLUMN "create_by" DROP NOT NULL;
ALTER TABLE "public"."adm_patient" ALTER COLUMN "create_by" DROP NOT NULL;
-- 添加更多表的处理...
最佳实践
1. 确保实体类继承基础类
所有实体类应继承 HisBaseEntity 或 BaseEntity:
@Data
@TableName("adm_practitioner")
public class Practitioner extends HisBaseEntity {
// 其他字段...
}
2. 检查安全上下文
确保在保存数据时有有效的安全上下文,这样自动填充处理器才能获取到当前用户信息。
3. 验证自动填充配置
确保 MybastisColumnsHandler 在Spring容器中被正确注册(使用@Component注解)。
总结
- 推荐保持数据库中的NOT NULL约束,确保数据完整性
- 依赖MyBatis-Plus的自动填充机制来设置审计字段
- 确保所有实体类继承基础实体类
- 在必要时才考虑移除数据库约束