java自定义注解不能直接执行sql,需结合反射与动态代理在运行时解析注解、提取sql、绑定参数并交由jdbc或orm执行;核心步骤为定义runtime保留注解→反射获取→参数安全绑定→整合到aop等执行链。

Java 自定义注解本身不能直接“执行”SQL,但可以配合反射 + 动态代理(如 MyBatis 的方式)或运行时解析,在方法/类被调用前读取注解内容,再根据注解值拼装或查找对应的 SQL 语句。核心思路是:**定义注解 → 在运行时通过反射获取注解信息 → 结合上下文(如参数、实体类)生成/定位 SQL → 执行 JDBC 或交由 ORM 框架处理**。
1. 定义可运行时保留的自定义 SQL 注解
注解需声明 @Retention(RetentionPolicy.RUNTIME),并按需支持方法或类型级别:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SqlMapping {
String value() default ""; // SQL 语句(支持占位符)
String id() default ""; // 唯一标识,用于从外部 SQL 管理器中查找
String dataSource() default "default"; // 可选数据源标识
boolean autoParam() default true; // 是否自动映射参数名到 #{} 占位符
}2. 运行时解析注解并提取 SQL
在拦截逻辑(如 AOP 切面、自定义 InvocationHandler)中,通过反射拿到目标方法及其注解:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 调用
method.getAnnotation(SqlMapping.class)获取注解实例 - 若
value()非空,直接使用该 SQL 字符串 - 若
id()非空,可查本地 Map、配置文件(如 sql-mapping.properties)或数据库表加载对应 SQL - 支持简单表达式替换:如将
#{userId}替换为实际参数值(注意防 SQL 注入,建议用 PreparedStatement 绑定)
3. 参数绑定与 SQL 安全组装
不推荐字符串拼接 SQL,应结合 PreparedStatement 实现动态绑定:
- 用正则提取 SQL 中的
#{xxx}占位符,得到参数名列表(如["userId", "status"]) - 从方法入参(如 Object[] 或 Map)中提取对应值,顺序或名称匹配
- 将原始 SQL 中
#{xxx}替换为?,再按顺序设置 PreparedStatement 参数 - 示例:
SELECT * FROM user WHERE id = #{id} AND status = #{status}→ 转为SELECT * FROM user WHERE id = ? AND status = ?
4. 整合到执行链(以 Spring AOP 为例)
定义一个切面,拦截带 @SqlMapping 的方法:
- 在
@Around中获取注解、SQL 和参数 - 创建
Connection和PreparedStatement,完成参数绑定 - 执行查询/更新,将结果转换为目标返回类型(可用泛型 + 反射构造对象)
- 异常时统一处理(如事务回滚、日志记录)
注意:生产环境建议复用现有框架能力(如 MyBatis 的 @Select),而非重复造轮子;自研主要用于学习原理或特殊轻量场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










