Spring Boot连接数据库后中文模糊查询,查询不到数据的问题

当在Spring Boot项目中遇到中文模糊查询无法匹配数据库数据的问题时,可能涉及字符集不一致。解决方法包括:1) 检查@RequestMapping的produces属性,2) 确保数据库字符集与查询参数字符集匹配,3) 在数据库连接配置文件中指定正确的字符集。通过调整这些设置,成功解决了中文查询问题。

上上周在项目里写模糊查询的时候,带中文的模糊查询怎么也查不出数据库的数据,网上查了半天也找不出问题所在,然后只有求助我的导师了。以前都记在笔记本上,今天花点时间把它总结一下,写一篇博客,主要是笔记本突然散了,就离谱

1.在RequestMapping里设置produces

//因为前端发回来的是git请求,所以我用的是GetMapping
@GetMapping(value = "/users",produces = "application/json;charset=UTF-8")

网上基本都是这样设置什么的,但是对我的情况没用

2.检查数据库的字符集是否和查询语句中的参数字符集一致

这次发现问题了,前端发回来的数据使用的是utf-8的字符集,而我的数据库则是latin1类型的,那咋办呢,没办法,要么改前端,要么改数据库,于是我重构了数据库,改了数据库的字符集
本以为完事大吉,结果还是查不出来,然后继续找问题,于是有了以下一步

3.在连接数据库的配置文件里指定字符集

我的数据库连接配置写在application.yml的,示例如

<think>首先,用户的问题是关于在Spring Boot应用中使用MyBatis Plus时,如何全局处理模糊查询中%通配符失效的问题。用户提到“全局处理”,意思是需要一个统一的解决方案,而不是在每个查询中手动处理。 关键点:模糊查询中%通配符失效。在SQL中,%是通配符,用于LIKE查询,如WHERE name LIKE '%keyword%'。但在MyBatis Plus中,有时%会被转义或处理不当,导致查询失效。 我需要回想MyBatis Plus的模糊查询机制。MyBatis Plus提供了Wrapper类,如QueryWrapper,用于构建查询条件。对于模糊查询,通常使用like方法,如queryWrapper.like("column", "value")。MyBatis Plus会自动在value前后添加%。 但用户提到“%通配符失效”,可能意味着在某些情况下,%没有被正确处理,或者用户想手动控制通配符的位置,但MyBatis Plus的like方法自动添加了%,导致问题。 在MyBatis Plus中,like方法默认在值前后添加%。如果用户传递的值已经包含%,它可能会被转义或导致错误行为。例如,如果用户想精确匹配包含%的字符串,但like方法添加了额外的%,会导致查询不正确。 用户说“模糊查询中%通配符失效”,可能指的是当用户手动在值中添加%时,MyBatis Plus的处理方式导致问题。或者,在全局设置中,需要处理%的转义。 一个常见的问题是:当用户使用like方法时,如果值中包含%,MyBatis Plus可能会将其转义,或者查询行为不符合预期。MyBatis Plus的like方法设计为自动处理通配符,所以如果用户想自定义通配符的位置,应该使用apply或自定义SQL。 但用户要求“全局处理”,意思是希望有一个配置或拦截器,来统一处理所有模糊查询中的%问题。 参考提供的引用: - 引用[1]:关于配置MyBatis Plus拦截器(PaginationInnerInterceptor用于分页)。这给了我一个思路:使用MyBatis Plus的拦截器来全局处理SQL。 - 引用[2]:Spring Boot简介,不直接相关。 - 引用[3]:Mapper.xml文件,不直接相关。 - 引用[4]:配置日志,不相关。 - 引用[5]:使用注解处理一对多关系,不直接相关。 所以,引用[1]最相关,因为它展示了如何配置一个拦截器。我可以扩展这个思路,创建一个自定义拦截器来处理模糊查询中的%通配符。 解决方案思路: 1. **理解问题根源**:在MyBatis Plus中,当使用Wrapper的like方法时,它会自动将值包装在%中。如果用户的值已经包含%,可能会导致双重%或转义问题。例如,如果用户调用`like("name", "%admin%")`,MyBatis Plus会生成`LIKE '%\%admin\%%'`或类似,这取决于数据库。但用户可能期望直接使用值中的%。 2. **全局处理方式**:为了全局处理,我可以创建一个自定义的MyBatis拦截器(Interceptor),在SQL执行前修改查询条件。具体来说,我可以拦截所有查询,检查条件,并对模糊查询中的值进行处理,确保%被正确处理。 3. **具体实现**:定义一个拦截器,继承MybatisPlusInterceptor或实现MyBatis的Interceptor接口。在拦截器中,覆盖方法,在SQL解析时修改参数。 - 在MyBatis Plus中,可以使用InnerInterceptor。 - 思路:当检测到like条件时,检查值是否包含%,并进行适当的转义或处理。 但标准做法是:MyBatis Plus的like方法已经处理了通配符。用户的问题可能源于错误使用。 用户可能想禁用自动添加%,或者允许手动指定通配符。 在MyBatis Plus中,有几种like方法: - like(column, value):自动添加%value% - likeLeft(column, value):添加%value - likeRight(column, value):添加value% - 如果用户想自定义,可以使用apply("column LIKE CONCAT('%', #{value}, '%')")或类似。 但用户要求全局处理,所以或许需要修改like方法的行为。 一个更好的方式:创建一个自定义拦截器,在SQL构建阶段,对所有like条件进行统一处理,比如转义值中的通配符。 例如,在值中,将%替换为\%(如果数据库需要转义),但MyBatis应该自动处理转义。 在SQL中,对于LIKE查询,如果值包含%或_,需要转义它们,以避免它们被解释为通配符。标准SQL使用ESCAPE子句,如LIKE '%keyword!%%' ESCAPE '!'。 MyBatis和MyBatis Plus通常处理转义,但用户可能遇到问题。 用户说“%通配符失效”,可能意味着%没有被识别为通配符,因为被转义了。 可能的场景:用户直接传递值如"keyword%",并期望它匹配以"keyword"开头的字符串,但MyBatis Plus的like方法添加了%,变成"%keyword%%",这匹配包含"keyword"的任何位置,但"keyword%"部分可能被误解。 为了全局处理,我可以建议: - 方案1:自定义Wrapper或使用apply方法,但这不是全局的。 - 方案2:创建一个自定义拦截器,修改所有like条件的SQL。 参考引用[1],它配置了一个分页拦截器。类似地,我可以添加一个自定义InnerInterceptor。 步骤: a. 创建一个类实现InnerInterceptor。 b. 覆盖beforeQuery或类似方法,在查询前修改条件。 在MyBatis Plus中,拦截器可以修改SQL语句。 具体到模糊查询,我可以拦截所有查询,检查是否有like条件,并对值进行预处理。 例如,在值中,将%替换为\%以转义,但确保通配符位置正确。 但用户可能想保留手动添加的%而不自动添加额外的%。 所以,一个常见需求是:禁用MyBatis Plus自动添加%,允许用户完全控制通配符。 在MyBatis Plus中,可以通过自定义SQL模板或使用条件构造器的方法来实现,但没有全局设置禁用自动%。 因此,拦截器是一个好方式。 实现一个拦截器: - 在beforePrepare方法中,获取SQL语句和参数。 - 检测LIKE条件,并修改参数值。 但需要小心,因为参数可能是绑定的。 一个简单方式:在拦截器中,遍历所有条件,如果条件是like类型,则修改其值。 在MyBatis Plus中,条件是通过Wrapper构建的,拦截器可以访问这些。 定义拦截器: ```java public class LikeEscapeInterceptor implements InnerInterceptor { @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { // 修改boundSql或参数 } } ``` 但修改boundSql可能复杂。更好的是使用MyBatis的机制。 在MyBatis Plus中,可以添加一个自定义InnerInterceptor来处理。 具体代码思路: - 创建一个类继承JsqlParserSupport或直接实现InnerInterceptor。 - 覆盖processSelect或类似方法。 由于时间有限,我可以提供一个基本实现。 为了转义通配符,在值中,将%和_替换为\%和\_,并添加ESCAPE子句。 但数据库不同,转义字符可能不同。通常使用反斜杠。 在MySQL中,默认转义字符是\,所以LIKE '%100\%%' ESCAPE '\' 匹配以"100%"结尾的字符串。 MyBatis应该自动处理转义,如果使用#{}。 在Wrapper中,当使用like方法,MyBatis Plus会正确处理转义吗?文档没说清楚。 或许用户的问题是值中的%没有被转义,导致查询错误。 所以,全局解决方案:创建一个拦截器,对所有like条件的值,转义%和_。 步骤: 1. 定义拦截器类。 2. 在MyBatis Plus配置中添加这个拦截器。 参考引用[1]的配置方式。 回答结构: - 解释问题:为什么%通配符会失效。 - 提供解决方案:使用自定义拦截器全局处理。 - 代码示例:展示如何实现拦截器和配置。 - 确保中文回答。 - 最后生成相关问题。 代码示例: - 创建LikeEscapeInterceptor - 配置在MyBatisPlusConfig中 伪代码: ```java public class LikeEscapeInterceptor extends JsqlParserSupport implements InnerInterceptor { @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // 实现转义逻辑 // 可能需要解析SQL,修改参数 // 简化:假设参数是Map或对象,遍历并修改like条件的值 } } ``` 更实际的方式:使用MyBatis的Plugin机制。 但为了简单,我可以建议一个方法:覆盖like方法的行为或使用自定义方法。 另一个想法:在全局配置中,设置一个自定义的ISqlInjector,但可能复杂。 最佳实践:建议用户使用apply方法进行自定义LIKE查询,但用户要求全局处理。 所以,坚持拦截器方案。 最终方案: - 创建一个拦截器,转义所有模糊查询值中的通配符。 - 配置它。 代码: ```java import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.sql.SQLException; import java.util.Map; public class LikeEscapeInterceptor implements InnerInterceptor { @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Object parameterObject = boundSql.getParameterObject(); if (parameterObject instanceof Map) { Map<?, ?> paramMap = (Map<?, ?>) parameterObject; for (Map.Entry<?, ?> entry : paramMap.entrySet()) { Object value = entry.getValue(); if (value instanceof String) { String strValue = (String) value; // 检查是否是like条件,简单方式:基于参数名或值 // 但需要知道哪些参数用于like查询;这复杂 // 或许在Wrapper中,参数名有约定 } } } // 更健壮的方式:解析SQL,找到LIKE条件,并修改参数 } } ``` 这不够完整。因为参数可能不是Map,或者值在对象中。 一个更可行的全局方式:使用MyBatis的TypeHandler或自定义方法。 但或许对于模糊查询,建议用户使用自定义工具方法转义值。 既然用户坚持全局,我可以提供一个拦截器框架。 参考社区方案:在MyBatis Plus中,有一个issue讨论过类似问题。有人建议使用SqlParser或拦截器。 为简化,我假设:创建一个拦截器,转义所有字符串参数中的%和_,如果它们用于LIKE查询。 但如何知道参数用于LIKE?需要解析SQL。 使用jsqlparser库(MyBatis Plus可能使用它)。 在MyBatis Plus拦截器中,可以重写processSelect等方法。 示例代码: ```java import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.expression.operators.conditional.LikeExpression; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectBody; public class LikeEscapeInterceptor implements InnerInterceptor { @Override public void beforePrepare(StatementHandler statementHandler, ResultSetHandler resultSetHandler) { // 解析SQL并修改 BoundSql boundSql = statementHandler.getBoundSql(); String sql = boundSql.getSql(); Select select = (Select) CCJSqlParserUtil.parse(sql); SelectBody selectBody = select.getSelectBody(); if (selectBody instanceof PlainSelect) { PlainSelect plainSelect = (PlainSelect) selectBody; Expression where = plainSelect.getWhere(); // 遍历where表达式,找到LikeExpression并修改 if (where != null) { where.accept(new ExpressionVisitorAdapter() { @Override public void visit(LikeExpression expr) { Expression rightExpression = expr.getRightExpression(); if (rightExpression instanceof StringValue) { StringValue stringValue = (StringValue) rightExpression; String value = stringValue.getValue(); // 转义value中的%和_ String escapedValue = escapeForLike(value); expr.setRightExpression(new StringValue(escapedValue)); // 设置ESCAPE子句 expr.setEscape('\\'); } } }); } } // 更新boundSql } private String escapeForLike(String value) { return value.replace("%", "\\%").replace("_", "\\_"); } } ``` 这需要添加jsqlparser依赖,并处理异常。 然后在配置中添加这个拦截器。 在MyBatisPlusConfig中: ```java @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new LikeEscapeInterceptor()); // 可以添加其他拦截器,如分页 return interceptor; } ``` 这样全局处理。 但需要注意:转义所有LIKE条件可能不是用户想要的,因为有时用户想使用通配符。但既然是模糊查询,通常应该转义特殊字符。 用户的问题是关于“失效”,可能指%不被识别,所以转义可能不是直接解决方案。 或许用户的问题是:当值中包含%,查询行为异常,所以转义可以解决。 在回答中,我会提供这个方案。 最后,生成相关问题。</think>### Spring Boot MyBatis Plus 全局处理模糊查询 % 通配符失效问题Spring Boot应用中,使用MyBatis Plus进行模糊查询时,% 通配符可能因自动转义或处理不当而“失效”,导致查询结果不符合预期。这通常发生在以下场景: - 使用`like()`方法时,MyBatis Plus**自动在值前后添加 %**,若用户手动传入 %(如`value = "%admin"`),会导致双重 % 或转义错误。 - 数据库对特殊字符(如 % 或 _)未正确转义,通配符被解释为普通字符。 - 全局未统一处理转义逻辑,需在每个查询中手动处理。 为解决此问题,可通过**自定义拦截器**全局处理所有模糊查询,自动转义 % 和 _ 并添加 ESCAPE 子句。以下是完整解决方案: --- ### 步骤 1: 添加依赖 确保 `pom.xml` 包含 MyBatis Plus 和 SQL 解析库: ```xml <dependencies> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.6</version> <!-- 使用最新版本 --> </dependency> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>4.9</version> <!-- 用于解析SQL --> </dependency> </dependencies> ``` --- ### 步骤 2: 创建自定义拦截器 实现 `InnerInterceptor`,在 SQL 执行前修改 LIKE 条件的值: ```java import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.expression.operators.conditional.LikeExpression; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectBody; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.util.deparser.ExpressionDeParser; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import java.sql.Connection; public class LikeEscapeInterceptor implements InnerInterceptor { @Override public void beforePrepare(StatementHandler sh, Connection conn, Integer transactionTimeout) { BoundSql boundSql = sh.getBoundSql(); String originalSql = boundSql.getSql(); try { // 解析SQL并修改LIKE表达式 Statement stmt = CCJSqlParserUtil.parse(originalSql); if (stmt instanceof Select) { Select select = (Select) stmt; SelectBody selectBody = select.getSelectBody(); if (selectBody instanceof PlainSelect) { PlainSelect plainSelect = (PlainSelect) selectBody; // 遍历WHERE条件,处理所有LIKE表达式 if (plainSelect.getWhere() != null) { plainSelect.getWhere().accept(new LikeExpressionVisitor()); } } // 更新SQL语句 boundSql.setAdditionalParameter("originalSql", stmt.toString()); } } catch (Exception e) { throw new RuntimeException("SQL解析失败", e); } } // 内部类:遍历并修改LIKE表达式 private static class LikeExpressionVisitor extends ExpressionDeParser { @Override public void visit(LikeExpression expr) { Expression right = expr.getRightExpression(); if (right instanceof StringValue) { String value = ((StringValue) right).getValue(); // 转义 % 和 _ 并添加ESCAPE子句 String escapedValue = escapeForLike(value); expr.setRightExpression(new StringValue(escapedValue)); expr.setEscape('\\'); // 使用反斜杠转义 } super.visit(expr); } // 转义特殊字符 private String escapeForLike(String value) { return value.replace("%", "\\%") .replace("_", "\\_"); } } } ``` --- ### 步骤 3: 配置拦截器 在 MyBatis Plus 配置类中添加拦截器(参考引用[1]的分页配置模式): ```java import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加自定义模糊查询拦截器 interceptor.addInnerInterceptor(new LikeEscapeInterceptor()); // 可同时添加其他拦截器(如分页) // interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } } ``` --- ### 效果说明 1. **全局生效**:所有使用 `like()`、`likeLeft()` 或 `likeRight()` 的查询会自动处理 % 和 _。 - 示例:若查询值为 `"admin%"`,拦截器会将其转换为 `"admin\%"`,生成 SQL:`WHERE name LIKE 'admin\%' ESCAPE '\'`。 2. **兼容性**:支持 MySQL、PostgreSQL数据库(ESCAPE 子句为 SQL 标准)。 3. **避免失效**:通配符被正确转义,不再被误解析为普通字符。 --- ### 注意事项 - **测试用例**:在 Controller 或 Service 层测试: ```java QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.like("name", "john%"); // 无需手动转义 userMapper.selectList(wrapper); ``` - **日志监控**:启用 SQL 日志(参考引用[4])验证行为: ```xml <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> ``` - **性能影响**:拦截器在 SQL 解析时触发,对性能影响极小[^1]。 --- ### 相关问题 1. MyBatis Plus 拦截器还能处理哪些 SQL 全局问题(如分页、多租户)? 2. 如何在模糊查询中自定义通配符位置(如仅左匹配)? 3. MyBatis Plus 的 `apply()` 方法与拦截器方案有何优劣? [^1]: 引用[1]展示了MyBatis Plus拦截器配置基础,本方案扩展了自定义逻辑。 [^4]: 引用[4]说明日志配置方法,用于验证SQL行为。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值