Java自定义注解仅作元数据标记,无法直接执行SQL;需结合AOP或MyBatis等框架,在运行时解析@SqlCondition注解并动态拼接WHERE条件,注意防范SQL注入、保障类型安全与可读性。

Java 中自定义注解本身不能直接执行 SQL 或拼接动态条件,它只是元数据标记;真正实现 SQL 片段动态拼接需要结合 AOP、注解处理器或 MyBatis 等框架能力。核心思路是:用注解声明意图(比如“这个参数参与 WHERE 条件”),再通过拦截/解析机制在运行时生成对应 SQL 片段。
用自定义注解标记查询参数
定义一个注解,用于标识某个方法参数应作为动态条件参与 SQL 构建:
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface SqlCondition {
String column() default ""; // 对应数据库字段名
String operator() default "="; // 比较操作符,如 "=", "LIKE", "IN"
boolean ignoreNull() default true; // 为 null 时是否跳过该条件
}
然后在 DAO 接口方法中使用:
List<User> findUsers(
@SqlCondition(column = "status") Integer status,
@SqlCondition(column = "name", operator = "LIKE") String name,
@SqlCondition(column = "age", operator = ">=", ignoreNull = false) Integer minAge
);
配合 AOP 在调用前动态生成 SQL
编写切面,拦截带 @SqlCondition 的方法,提取参数并构造 WHERE 子句:
立即学习“Java免费学习笔记(深入)”;
- 通过
JoinPoint获取方法签名和实际参数值 - 反射读取每个参数上的
@SqlCondition注解信息 - 根据
ignoreNull和值是否为空决定是否加入条件 - 对
LIKE自动补上%...%,对IN处理集合展开 - 将拼好的 SQL 片段存入线程局部变量(如
ThreadLocal<String>)或封装进上下文对象,供后续 SQL 执行器使用
与 MyBatis 集成(推荐更实用的方案)
MyBatis 原生支持动态 SQL,自定义注解可作为轻量级语法糖,最终仍交由 <if>、<choose> 等标签处理:
- 定义注解仅用于生成 Mapper XML 中的占位逻辑(如生成
<if test="status != null">AND status = #{status}</if>) - 配合 MyBatis 的
@SelectProvider,写一个SqlProvider类,在其方法中解析注解 + 参数,返回完整 SQL 字符串 - Provider 方法内可复用前面 AOP 中的条件拼接逻辑,保持一致性
示例 Provider:
public class UserSqlProvider {
public String findUsers(Map<String, Object> params) {
StringBuilder sql = new StringBuilder("SELECT * FROM user WHERE 1=1");
// 解析 params 中的注解元数据(需提前注入或约定 key 名)
if (params.containsKey("status") && params.get("status") != null) {
sql.append(" AND status = #{status}");
}
if (params.containsKey("name") && StringUtils.hasText((String) params.get("name"))) {
sql.append(" AND name LIKE CONCAT('%', #{name}, '%')");
}
return sql.toString();
}
}
注意事项与边界情况
这类设计容易引入隐患,需特别注意:
-
SQL 注入风险:禁止直接字符串拼接用户输入,所有参数必须用
#{}占位符,避免${} -
类型安全缺失:注解无法校验
column是否真实存在,建议配合代码生成或启动时扫描校验 - 复杂逻辑受限:多表 JOIN、子查询、排序分页等不适合全靠注解驱动,应保留 XML 或 Script 方式
- 可读性权衡:过度依赖注解会让查询逻辑分散,团队需统一规范,必要时辅以文档或 IDE 插件支持


















