mybatis注解模糊查询的两种方式

本文详细介绍了MyBatis中两种参数占位符的使用方法:一种是通过#{name}

第一种 拼接字符串

@Select("select * from xxx where name like #{name} ")

List findByName(String name)

测试的时候,传入的参数要拼接为

userDao.findByName("%name%")

第二种 占位符

@Select("select * from xxx where name like ‘%${value}%’ ")

List findByName(String name)

测试的时候,直接传入参数

userDao.findByName(name)

转自

https://www.cnblogs.com/hcl763088301/p/11228878.html

(转载以记录)

<think>我们被要求使用MyBatis的@Select注解来实现动态SQL模糊查询。根据引用[1]中的示例,我们可以使用`<script>`标签来编写动态SQL。在模糊查询中,我们通常使用LIKE语句,并且为了避免SQL注入,我们使用#{}来传递参数,同时使用concat函数来拼接通配符。 引用[1]中的示例: @Select({ "<script>", "SELECT * FROM user", "WHERE 1=1", "<when test='name!=null and name!=\"\"'>", "AND name LIKE concat('%',#{name},'%')", "</when>", "</script>" }) public List<User> getUserList(String name); 注意:这里使用了`<when>`标签来动态添加条件,当name不为null且不为空字符串时,才会添加该条件。 但是,我们也可以使用`<if>`标签,因为`<when>`通常用在`<choose>`内部,而单个条件判断用`<if>`即可。 因此,我们可以这样写: ```java @Select({ "<script>", "SELECT * FROM user", "WHERE 1=1", "<if test='name != null and name != \"\"'>", "AND name LIKE CONCAT('%', #{name}, '%')", "</if>", "</script>" }) List<User> getUserList(@Param("name") String name); ``` 注意:这里使用了`@Param`注解来指定参数名,确保在XML中能够正确引用。但是,在注解使用`@Param`是必须的,因为我们在动态SQL的test表达式中使用了`name`,所以需要将方法参数通过`@Param`命名为"name"。 另外,引用[2]中展示了另一种写法,但它是处理IN条件,与模糊查询不同,不过我们可以参考其动态SQL的结构。 如果不想使用`<script>`标签,MyBatis还提供了其他注解如`@SelectProvider`来编写更复杂的动态SQL,但根据要求,我们使用@Select注解并内嵌<script>的方式。 另外,注意在字符串中拼接SQL片段时,要确保语句的正确性。在Java字符串中,双引号需要转义,但上面的例子中已经使用了单引号包裹test表达式,所以内部的双引号使用转义(\"\")表示空字符串。 但是,在test表达式中,我们也可以使用单引号来表示字符串,这样内部的双引号就不需要转义了。例如: test="name != null and name != ''" 所以,我们可以这样写,避免转义双引号: ```java @Select({ "<script>", "SELECT * FROM user", "WHERE 1=1", "<if test=\"name != null and name != ''\">", // 这里使用双引号包裹整个test表达式,那么内部字符串用单引号 "AND name LIKE CONCAT('%', #{name}, '%')", "</if>", "</script>" }) List<User> getUserList(@Param("name") String name); ``` 或者,为了在Java字符串中避免转义,我们也可以将整个test表达式用单引号包裹,内部字符串用双引号(但内部字符串为空时,用两个单引号表示空字符串可能会引起混淆,所以通常用转义双引号表示空字符串,或者内部字符串用单引号): 推荐写法(使用单引号包裹test表达式,内部字符串用双引号): test='name != null and name != ""' 但是,在Java字符串中,双引号不需要转义,所以我们可以这样写: ```java @Select({ "<script>", "SELECT * FROM user", "WHERE 1=1", "<if test='name != null and name != \"\"'>", // 这里用单引号包裹test表达式,内部双引号需要转义 "AND name LIKE CONCAT('%', #{name}, '%')", "</if>", "</script>" }) List<User> getUserList(@Param("name") String name); ``` 或者,内部字符串用单引号表示空字符串(注意:在MyBatis的动态SQL中,空字符串可以用''表示,所以我们可以这样写): ```java @Select({ "<script>", "SELECT * FROM user", "WHERE 1=1", "<if test='name != null and name != \"\"'>", // 或者使用两个单引号表示空字符串,但注意在Java字符串中,两个连续的单引号是允许的,但这样写可能不太清晰,所以通常用转义双引号 // 或者这样写:<if test='name != null and name != ""'> 但是这样在Java字符串中,双引号不需要转义,所以可以直接写,但外部用单引号包裹,内部双引号不会冲突。 // 实际上,在外部单引号包裹的字符串中,内部的双引号不需要转义,所以可以写成:<if test='name != null and name != ""'> "AND name LIKE CONCAT('%', #{name}, '%')", "</if>", "</script>" }) List<User> getUserList(@Param("name") String name); ``` 但是,为了避免混淆,我们通常采用外部用双引号,内部字符串用单引号的方式,并且对双引号进行转义(如第一种方式),或者外部用单引号,内部字符串用双引号(但需要转义内部的双引号,因为内部双引号在Java字符串中需要转义)。这看起来有点混乱,我们选择一种清晰的方式。 实际中,我们经常看到这样的写法: ```java @Select({ "<script>", "SELECT * FROM user", "WHERE 1=1", "<if test=\"name != null and name != ''\">", // 外部双引号,内部字符串用单引号(表示空字符串) "AND name LIKE CONCAT('%', #{name}, '%')", "</if>", "</script>" }) List<User> getUserList(@Param("name") String name); ``` 这种写法在Java字符串中,双引号包裹整个test表达式,内部字符串用单引号,这样空字符串就是'',不需要转义,且清晰。 总结:推荐使用外部双引号,内部字符串用单引号,这样在Java字符串中不需要对双引号进行转义,且内部单引号不会与外部冲突。 另外,注意:在MySQL中,CONCAT函数可以拼接多个字符串,这里我们拼接了'%'、参数和'%',形成%参数%的格式,即前后模糊匹配。 如果数据库是Oracle,则可以使用`'%' || #{name} || '%'`,但这里假设是MySQL。 因此,最终代码为: ```java @Select({ "<script>", "SELECT * FROM user", "WHERE 1=1", "<if test=\"name != null and name != ''\">", " AND name LIKE CONCAT('%', #{name}, '%')", "</if>", "</script>" }) List<User> getUserList(@Param("name") String name); ``` 注意:这里使用了`WHERE 1=1`来避免判断第一个条件时出现AND问题,也可以使用`<where>`标签来动态处理WHERE关键字,但这里为了简单使用了1=1。 使用`<where>`标签的写法: ```java @Select({ "<script>", "SELECT * FROM user", "<where>", " <if test=\"name != null and name != ''\">", " name LIKE CONCAT('%', #{name}, '%')", " </if>", "</where>", "</script>" }) List<User> getUserList(@Param("name") String name); ``` 这样,当没有条件时,WHERE关键字不会出现;有条件时,WHERE关键字会自动加上,并且会处理第一个条件前的AND或OR(去掉或保留)。但是注意,在`<where>`标签内部,如果条件前面有AND或OR,MyBatis会在拼接时自动去掉第一个条件前的AND或OR。所以,如果我们在条件中写了AND,那么它可能被去掉,导致语法错误。因此,在`<where>`标签内部的条件中,不应该在开头添加AND或OR。 但是,如果只有一个条件,且写在`<where>`标签内,那么直接写条件即可,不需要AND。如果有多个条件,则第一个条件前不能有AND,后面的条件前要有AND。 所以,如果我们只有一个条件,可以这样写: ```java @Select({ "<script>", "SELECT * FROM user", "<where>", " <if test=\"name != null and name != ''\">", " name LIKE CONCAT('%', #{name}, '%')", " </if>", "</where>", "</script>" }) List<User> getUserList(@Param("name") String name); ``` 如果有多个条件,例如还要根据年龄查询: ```java @Select({ "<script>", "SELECT * FROM user", "<where>", " <if test=\"name != null and name != ''\">", " name LIKE CONCAT('%', #{name}, '%')", " </if>", " <if test=\"age != null\">", " AND age = #{age}", " </if>", "</where>", "</script>" }) List<User> getUserList(@Param("name") String name, @Param("age") Integer age); ``` 注意:第二个条件前有AND,但MyBatis的`<where>`标签会智能处理:如果第一个条件不满足,第二个条件满足,那么它会自动去掉第二个条件前的AND。所以,这样写是安全的。 因此,对于模糊查询,我们可以根据实际需求选择使用`<where>`标签还是使用1=1的方式。 综上所述,我们提供了两种写法,用户可以根据自己的喜好选择。 最后,注意在MyBatis中,使用注解方式编写动态SQL时,需要确保MyBatis的版本支持(通常3.3.0以上)。 引用标识:我们参考了引用[1]中的模糊查询写法,并进行了适当的调整和说明[^1]。</think>在 MyBatis使用 `@Select` 注解实现动态 SQL 模糊查询,可通过 **`<script>` 标签结合 OGNL 表达式**完成。以下是具体实现方法: ### 核心解决方案 ```java @Select({ "<script>", "SELECT * FROM user", "WHERE 1=1", "<if test='name != null and name != \"\"'>", // 动态判断参数 " AND name LIKE CONCAT('%', #{name}, '%')", // 模糊查询语法 "</if>", "</script>" }) List<User> searchUsers(@Param("name") String name); ``` ### 关键说明 1. **`<script>` 标签** 包裹整个 SQL 语句,启用 MyBatis 动态 SQL 解析功能。 2. **`<if>` 条件判断** - `test` 属性使用 OGNL 表达式判断参数有效性 - `name != null and name != ""` 确保参数非空 - 注意字符串空值判断需用转义双引号 `\"\"` 3. **模糊查询语法** - `CONCAT('%', #{name}, '%')` 生成 `%keyword%` 格式 - 避免直接写 `LIKE '%${name}%'`(有 SQL 注入风险) 4. **`@Param` 注解** 方法参数必须添加 `@Param("name")`,使 OGNL 能识别 `name` 变量 ### 优化写法(使用 `<where>` 标签) ```java @Select({ "<script>", "SELECT * FROM user", "<where>", " <if test='name != null and name != \"\"'>", " name LIKE CONCAT('%', #{name}, '%')", " </if>", "</where>", "</script>" }) List<User> searchUsers(@Param("name") String name); ``` - **优势**:自动处理 `WHERE` 关键字,无需 `1=1` - **注意**:`<where>` 标签内条件**不能**以 `AND/OR` 开头 ### 注意事项 1. **防 SQL 注入** 必须使用 `#{name}` 参数化查询,禁止 `${name}` 拼接 2. **多条件扩展** 可追加 `<if>` 块实现多条件查询,例如: ```xml <if test='age != null'> AND age = #{age} </if> ``` 3. **数据库兼容性** - MySQL:`CONCAT('%', #{name}, '%')` - Oracle:`'%' || #{name} || '%'` - SQL Server:`'%' + #{name} + '%'` ### 示例场景 ```java // 调用示例 1:有查询条件 List<User> users = userMapper.searchUsers("Tom"); // 执行SQL: SELECT * FROM user WHERE name LIKE '%Tom%' // 调用示例 2:无查询条件 List<User> users = userMapper.searchUsers(null); // 执行SQL: SELECT * FROM user ``` > **提示**:当 SQL 较复杂时,推荐改用 XML 映射文件,维护性更佳[^1][^2]。 --- ### 相关问题 1. MyBatis 中 `@Select` 注解如何实现 `IN` 条件查询? 2. 动态 SQL 中 `<where>` 和 `<if>` 标签有什么区别? 3. 如何防止 MyBatis 动态 SQL 中的 SQL 注入漏洞? 4. MyBatis 模糊查询时,`#{}` 和 `${}` 有哪些区别? 5. 除了 `@Select` 注解,还有哪些方式实现 MyBatis 动态 SQL? [^1]: 引用自 MyBatis 动态 SQL 官方文档 [^2]: 参考 MyBatis 注解最佳实践指南
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值