# 关于数据库审计字段(create_by, create_time等)的处理方案 ## 问题描述 在使用OpenHIS系统时,可能会遇到如下错误: ``` org.postgresql.util.PSQLException: ERROR: null value in column "create_by" of relation "adm_practitioner" violates not-null constraint ``` ## 问题分析 1. 数据库表中的审计字段(如create_by, create_time)设置了NOT NULL约束 2. 应用程序层面使用了MyBatis-Plus的自动填充功能来设置这些字段 3. 当自动填充机制失效时,就会出现违反非空约束的错误 ## 解决方案 ### 方案一:修复自动填充机制(推荐) 系统已经实现了自动填充机制,位于 `MybastisColumnsHandler.java`: ```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,可以移除数据库约束: ```sql -- 移除 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; ``` ### 方案三:批量修复所有表的约束 如果多个表都存在这个问题,可以使用以下脚本: ```sql -- 为所有表的审计字段移除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`: ```java @Data @TableName("adm_practitioner") public class Practitioner extends HisBaseEntity { // 其他字段... } ``` ### 2. 检查安全上下文 确保在保存数据时有有效的安全上下文,这样自动填充处理器才能获取到当前用户信息。 ### 3. 验证自动填充配置 确保 `MybastisColumnsHandler` 在Spring容器中被正确注册(使用@Component注解)。 ## 总结 - 推荐保持数据库中的NOT NULL约束,确保数据完整性 - 依赖MyBatis-Plus的自动填充机制来设置审计字段 - 确保所有实体类继承基础实体类 - 在必要时才考虑移除数据库约束