MyBatis 动态 SQL 语句中出现 '<' 的问题
问题描述
映射接口方法如下:
/**
* 根据姓名和年龄查询用户信息
* @param name 姓名
* @param user 获取年龄
* @return
*/
public List<UserEntity> selectUserByNameAndAge(@Param("name") String name, @Param("user")
UserEntity user);
SQL 语句映射如下:
<select id="selectUserByNameAndAge" resultMap="userResultMap">
select * from tb_user where name = #{name} and age < #{user.age};
</select>
单元测试方法如下:
@Test
public void selectUserByNameAndAgeTest() {
UserEntity user = new UserEntity();
user.setAge(30);
List<UserEntity> userEntities =
userMapper.selectUserByNameAndAge("李四",user);
System.out.println(userEntities);
Assert.assertNotNull(userEntities);
}
执行测试结果如下:
org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### The error may exist in mappers/UserMapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 29; columnNumber: 61; 元素内容必须由格式正确的字符数据或标记组成。
Process finished with exit code -1
问题分析
从报错信息显示,问题应该出在映射文件 UserMapper.xml 中,更具体说,是该文件的 29 行,这一行内容如下:
select * from tb_user where name = #{name} and age < #{user.age};
这正好是映射接口方法对应的 SQL 语句,这条语句结构还算简单的,仔细看了一下似乎没啥问题,但是为何编译时却报这条语句有问题呢?
首先,我们可以先假设编译器没有乱报错,这条 SQL 语句确实有问题,只是我们目前不知道具体问题出在哪里?
然后,我们可以将这条 SQL 语句进行简化,将内容修改如下:
select * from tb_user
可能你会有疑问,你这是干嘛呀,我这样做是想验证这条 SQL 语句到底哪里有问题。
执行测试,结果如下:
[UserEntity{id=1, userName='张三', password='123456', name='张三', age=22, sex=1, birthday=Sun Sep 02 00:00:00 IRKST 1990, created='2020-06-17 09:30:58.0', updated='2020-06-17 09:30:58.0', interests=null}, UserEntity{id=2, userName='ls', password='123456', name='李四', age=24, sex=1, birthday=Sun Sep 05 00:00:00 IRKST 1993, created='2020-06-17 09:30:58.0', updated='2020-06-17 09:30:58.0', interests=null}, UserEntity{id=5, userName='lx', password='123456', name='刘星', age=21, sex=1, birthday=Fri Jan 10 00:00:00 IRKT 1992, created='2020-06-24 17:25:23.0', updated='2020-06-24 17:25:23.0', interests=null}, UserEntity{id=6, userName='ww', password='123456', name='王五', age=21, sex=1, birthday=Fri Jan 10 00:00:00 IRKT 1992, created='2020-06-24 18:53:48.0', updated='2020-06-24 18:53:48.0', interests=null}, UserEntity{id=7, userName='zq', password='123456', name='张倩', age=21, sex=0, birthday=Mon Jul 05 00:00:00 IRKST 1993, created='2020-07-05 09:24:39.0', updated='2020-07-05 09:24:43.0', interests=null}, UserEntity{id=8, userName='ll', password='123456', name='刘丽', age=23, sex=0, birthday=Fri Jul 05 00:00:00 IRKST 1991, created='2020-07-05 09:25:44.0', updated='2020-07-05 09:25:47.0', interests=null}]
这说明简化以后的这条 SQL 语句执行没有问题,当然也不应该有什么问题,如果这么简单一条 SQL 语句都有问题,那可以推测 MyBatis 开发环境可以出了问题,那么应该所有的接口方法都会报错。
接着,我们在这条 SQL 语句基础上再添加一些条件,如下:
select * from tb_user where name = #{name}
执行测试,结果也没问题,我这里就不打印出来了。
走到这里,相信你应该清楚了,通过前两个测试,我已经缩小了问题的范围,可以 100% 确定是 and age < #{user.age} 这里出的问题。
那究竟是哪里出了问题,我首先猜测最可能就是参数传递。为了验证我的想法是否正确,我将参数传递写死,如下:
select * from tb_user where name = #{name} and age < 30;
执行测试,结果如下:
org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### The error may exist in mappers/UserMapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 29; columnNumber: 57; 元素内容必须由格式正确的字符数据或标记组成。
Process finished with exit code -1
居然还报错,直接打脸,这说明猜测的参数传递错误是不对的,问题原因还是没有找到。
走到这里,估计很多初学者都快失去的耐心了,心里想这也太坑了吧,估计自己是搞不定啦。别灰心,也许我们离成功只有一步之遥。
重新整理一下思路,现在我们能够确认的是 and age < 30 这里有问题,但是确实想不出究竟问题出在哪里。
我打算再做一次尝试,再次修改这条 SQL 语句如下:
select * from tb_user where name = #{name} and age = 30;
和之前相比,无非就是把 ’<' 符号 改为 '=’ 符号而已,之所以这样改,是因为也没地方可改了,死马当成活马医。
执行测试,结果如下:
[]
居然没报错,直接打印空集合,这真是有意想不到的收获呀。
分析到现在,我们终于找到了问题的原因,原来搞了半天就是 '<' 符号惹的祸。
既然 '<' 符号有问题,那么自然会联想到 ‘>' 符号是不是也有问题,修改如下:
select * from tb_user where name = #{name} and age > 30;
执行接错,结果如下:
[]
没报错,说明 '>' 符号没有问题。
还不死心,再试一试 ‘<=' 符号,结果显示和 ’<' 符号一样报错。
现在问题已经再清晰不过了,'<' 符号和 '<=' 符号不能直接在映射文件中使用。
问题解决
分析问题出在哪里,解决问题就变得比较简单了。
最简单的办法就是百度,搜索 ”MyBatis SQL 语句中出现 ’<’ 的解决方案",相信你会找到一堆解决方案,剩下的就是测试一下哪个正确罢了,我非常鼓励你动手去找,虽然有点麻烦,但是可以锻炼你的独立解决问题能力,提升自我成就感。
当然,我也会在下面提供答案,这些答案也是我在网上收集的,而且是验证 OK
解决方法一
字符转义
以上这张表就是 MyBatis 映射文件特殊字符转义表,'<' 符号在 XML 映射文件中其实是特殊字符,因为它和映射文件中的标记符号 ’< / >' 无法区别,所以需要用转义字符把它替换掉。
那么,'<' 问题解决办法如下:
select * from tb_user where name = #{name} and age < #{user.age};
执行测试,正确显示结果,问题搞定。
解决方法二
使用
在使用 mybatis 时我们 SQL 语句是写在 XML 映射文件中,如果 SQL 语句中有一些特殊的字符的话,在解析 XML 文件的时候会被转义,但我们不希望它被转义,所以我们可以使用来解决。
是什么,这是XML语法。在CDATA内部的所有内容都会被解析器忽略,只简单当做字符串处理。
那么,'<' 问题解决办法如下:
select * from tb_user where name = #{name} and age <![CDATA[ < ]]> #{user.age};
执行测试,OK
问题总结
- 通过以上问题分析过程,其实我已经向你展示了我在实际项目开发中常用的排错方法之一,我给它取名缩小范围法。希望初学者能够明白,授人以鱼不如授人以渔,掌握一个方法远比记住一个知识点更为重要。
- 如果你懂一些 HTML 静态网页的知识,应该很容易想明白在映射文件中的 SQL 语句中为何 '<' 符号会报错。而且上面那张特殊字符转义表,你也会似曾相识,因为它也是 HTML 静态页面的特殊字符转义表。的作用在 HMTL 中也是相同的。说这些,我想表达的是知识之间是有关联的,明白之间的关联就可以举一反三、触类旁通。
MyBatis 动态 SQL 语句中出现 '<' 的问题的更多相关文章
- Mybatis中动态SQL语句中的parameterType不同数据类型的用法
Mybatis中动态SQL语句中的parameterType不同数据类型的用法1. 简单数据类型, 此时#{id,jdbcType=INTEGER}中id可以取任意名字如#{a,jdbcType ...
- mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句
mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类:1. if 语句 (简单的条件判断)2. c ...
- Mybatis 动态Sql语句《常用》
MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格,还要注意省掉 ...
- mybatis 动态sql语句(3)
mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类: 1. if 语句 (简单的条件判断) 2. ...
- mybatis 动态sql语句(1)
mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类: 1. if 语句 (简单的条件判断) 2. ...
- 【转】mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句
转自:除非申明,文章均为一号门原创,转载请注明本文地址,谢谢! 转载地址:http://blog.csdn.net/kutejava/article/details/9164353#t5 1. if ...
- 7. mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句
转自:http://www.kyjszj.com/htzq/79.html 1. if 语句 (简单的条件判断) 2. choose (when,otherwize) ,相当于java 语言中的 sw ...
- mybatis 动态sql语句(2)
什么是动态SQL MyBatis的一个强大特性之一通常是它的动态SQL能力.如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的 ...
- MyBatis学习总结(11)——MyBatis动态Sql语句
MyBatis中对数据库的操作,有时要带一些条件,因此动态SQL语句非常有必要,下面就主要来讲讲几个常用的动态SQL语句的语法 MyBatis中用于实现动态SQL的元素主要有: if choose(w ...
随机推荐
- 通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
之前的章节我们介绍了如何通过dapr发起一个服务调用,相信看过前几章的小伙伴已经对dapr有一个基本的了解了,今天我们来聊一聊dapr的另外一个功能--订阅发布 目录:一.通过Dapr实现一个简单的基 ...
- Leedcode算法专题训练(数学)
204. 计数质数 难度简单523 统计所有小于非负整数 n 的质数的数量. class Solution { public int countPrimes(int n) { boolean[] is ...
- JavaFX获取屏幕尺寸
1 awt Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); double width = screenSize. ...
- Go-18-自动下载所有依赖包
如何自动下载所有依赖包? 大部分情况下大家下载 Go 项目都是使用go get命令,它除了会下载指定的项目代码,还会去下载这个项目所依赖的所有项目. 但是有的时候我们的项目由于各种原因并不是通过go ...
- [BUAA2021软工助教]案例分析作业总结
目录 一.作业链接 二.优秀作业推荐 A+作业推荐 A作业推荐 三.总结 所有案例分析总结 特色与优点 问题与建议 不同类产品案例分析Bug汇总 CSDN问答社区.Stack Overflow.Seg ...
- 反病毒攻防研究第005篇:简单木马分析与防范part1
一.前言 病毒与木马技术发展到今天,由于二者总是相辅相成,你中有我,我中有你,所以它们之间的界限往往已经不再那么明显,相互之间往往都会采用对方的一些技术以达到自己的目的,所以现在很多时候也就将二者直接 ...
- hdu1686 最大匹配次数 KMP
题意: 给你两个串,问你串a在串b中出现了多少次. 思路: 直接匹配,KMP时匹配到匹配串的最后一个的时候不用跳出,直接匹配就行了,最后一个'/0'不会和目标串匹配,所以经过ne ...
- Day004 顺序结构
顺序结构 JAVA的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行. 顺序结构是最简单的算法结构. 语句与语句之间,是按照从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的,它 ...
- Maven不扫描java文件夹下的配置文件解决办法
<build> <resources> <resource> <directory>src/main/java</directory> &l ...
- JDBC相关配置和操作
获取数据库连接的几种方式 ps.数据库URL : String url = "jdbc:mysql://localhost:3306/dailytext?useSSL=false&s ...