Java JDBC 层本身不支持注解驱动的 SQL 自动增强,因其是底层 API,无内置注解处理机制;必须在 MyBatis、JPA 等上层框架或通过 DataSource/Connection 代理实现,纯 JDBC 无法直接用注解完成 INSERT 字段自动填充。

Java 中 JDBC 层本身不支持注解驱动的 SQL 自动增强,因为 JDBC 是底层 API,没有内置的注解处理或拦截机制。要实现“为所有 INSERT 语句自动追加创建时间与创建人字段”,必须在 JDBC 上层(如 MyBatis、JPA/Hibernate)或自定义 JDBC 拦截器(如通过 java.sql.Connection 代理或 DataSource 代理)中实现。纯 JDBC 无法直接用注解做到这一点。
使用 MyBatis + 拦截器(推荐且实用)
MyBatis 提供了完整的插件(Interceptor)机制,可在 SQL 执行前动态改写 SQL 和参数,配合实体类上的自定义注解,就能实现字段自动填充。
- 定义注解,标记需要自动填充的字段:
- 在实体类上使用:
<strong>@AutoFill("create_time")</strong>
private LocalDateTime createTime;
<strong>@AutoFill("create_by")</strong>
private String createBy;
// getter/setter...} ```
- 编写 MyBatis 插件,拦截
Executor.update方法,在 INSERT 前解析 SQL、注入字段和值: - 利用
MetaObject获取参数对象,扫描带@AutoFill的字段,提取当前登录用户(需自行提供上下文,如 ThreadLocal 存储)、系统时间; - 使用
SqlParser(或正则)安全地改写 INSERT 语句:匹配INSERT INTO table (...) VALUES (...),在括号内追加字段名与占位符,并向ParameterHandler注入对应值; - 注意兼容
INSERT INTO ... SELECT或无字段列表的INSERT INTO table VALUES (...)场景,建议强制要求显式字段列表。
基于 DataSource 的 JDBC 层代理(更底层但通用)
若不用 ORM,坚持在纯 JDBC 层统一处理,可包装 DataSource,返回代理的 Connection → 代理 PreparedStatement,在 executeUpdate() 前解析并改写 SQL。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 核心逻辑:识别以
INSERT INTO开头(忽略空格/换行/注释)、且含括号字段列表的语句; - 用轻量级 SQL 解析器(如
net.sf.jsqlparser)解析 AST,安全插入字段和值表达式(如NOW()、'admin'); - 创建人信息需从调用线程上下文获取(例如 Spring 的
SecurityContextHolder或自定义CurrentUserHolder); - 缺点:性能开销略大、SQL 解析有兼容性风险(尤其复杂嵌套或方言),且无法感知 Java 对象结构,需约定表字段命名规则(如所有表都有
create_time字段)。
替代方案:数据库默认值 + 应用层兜底
更简洁可靠的做法是分层协作:
立即学习“Java免费学习笔记(深入)”;
- 数据库层面设默认值:
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,create_by VARCHAR(64) DEFAULT 'system'; - 应用层(如 Spring AOP 或 BaseEntity 模板)在 insert 前主动设置值,避免依赖 SQL 改写;
- 结合 Hibernate
@PrePersist或 MyBatis Plus 的MetaObjectHandler—— 它们本质也是拦截,但封装成熟、稳定、易测试。
为什么不建议在 JDBC Driver 层做?
JDBC Driver(如 MySQL Connector/J)虽支持 statement interceptor(如 mysql.jdbc.interceptors 参数),但属于厂商私有扩展,缺乏标准、难维护、调试困难,且无法访问业务上下文(如当前用户),仅适合日志或监控类场景,不适合业务字段填充。

















