问题描述

映射接口方法如下:

 /**
* 根据姓名和年龄查询用户信息
* @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 &lt; #{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 语句中出现 '<' 的问题的更多相关文章

  1. Mybatis中动态SQL语句中的parameterType不同数据类型的用法

    Mybatis中动态SQL语句中的parameterType不同数据类型的用法1. 简单数据类型,    此时#{id,jdbcType=INTEGER}中id可以取任意名字如#{a,jdbcType ...

  2. mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句

    mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类:1. if 语句 (简单的条件判断)2. c ...

  3. Mybatis 动态Sql语句《常用》

    MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格,还要注意省掉 ...

  4. mybatis 动态sql语句(3)

    mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类: 1. if 语句 (简单的条件判断) 2. ...

  5. mybatis 动态sql语句(1)

    mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类: 1. if 语句 (简单的条件判断) 2. ...

  6. 【转】mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句

    转自:除非申明,文章均为一号门原创,转载请注明本文地址,谢谢! 转载地址:http://blog.csdn.net/kutejava/article/details/9164353#t5 1. if ...

  7. 7. mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句

    转自:http://www.kyjszj.com/htzq/79.html 1. if 语句 (简单的条件判断) 2. choose (when,otherwize) ,相当于java 语言中的 sw ...

  8. mybatis 动态sql语句(2)

    什么是动态SQL MyBatis的一个强大特性之一通常是它的动态SQL能力.如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的 ...

  9. MyBatis学习总结(11)——MyBatis动态Sql语句

    MyBatis中对数据库的操作,有时要带一些条件,因此动态SQL语句非常有必要,下面就主要来讲讲几个常用的动态SQL语句的语法 MyBatis中用于实现动态SQL的元素主要有: if choose(w ...

随机推荐

  1. 请使用管理员权限执行pip install命令

    重要的事情说三遍! 请使用管理员权限执行pip install命令 请使用管理员权限执行pip install命令 请使用管理员权限执行pip install命令 踩坑记录 当时一切还是从一题Misc ...

  2. Android+Spring Boot 选择+上传+下载文件

    2021.02.03更新 1 概述 前端Android,上传与下载文件,使用OkHttp处理请求,后端使用Spring Boot,处理Android发送来的上传与下载请求.这个其实不难,就是特别多奇奇 ...

  3. java7与java9中的try-finally关闭资源

    1.java7中的try 在java7之前,对于一些需要使用finally关闭资源的操作,会显得很臃肿. try { // } catch(Exception e) { // } finally { ...

  4. Hadoop完整搭建过程(二):伪分布模式

    1 伪分布模式 伪分布模式是运行在单个节点以及多个Java进程上的模式.相比起本地模式,需要进行更多配置文件的设置以及ssh.YARN相关设置. 2 Hadoop配置文件 修改Hadoop安装目录下的 ...

  5. Jenkins 自定义构建结果

    1. Jenkins 构建原理 2. 脚本执行失败立即停止执行 3. 脚本执行失败继续后面的执行但最终的结果是构建失败 1. Jenkins 构建原理 Jenkins 的构建成功和脚本执行成功是两个事 ...

  6. MySQL数据库干货分享!unsigned使用案例分析

    今天主要写一下unsigned的使用,进入正文前先分享一套博主觉得讲的很详细很实用的MySQL教程给大家 https://www.bilibili.com/video/BV1fx411X7BD 好了, ...

  7. 记canvas画笔笔迹的多次优化过程

    我们的项目是面向学校老师的教学软件,所以肯定少不了互动白板的功能,而这个里面的画笔功能是由我来开发的,下面介绍这个过程中遇到的问题以及解决方法. 首先给大家明确下由于软件中的画布可以自由移动,会超出屏 ...

  8. 软件调研——GoodNotes 5与Notability

    项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 作业要求 我在这个课程的目标是 积累软件开发经验,提高工程能力 这个作业在哪个具体方面帮助我实现目标 深入调 ...

  9. vagrant构建centos虚拟环境

    vagrant搭建centos 什么是vagrant 如何使用 1.构建本地的目录 2.官方下载对应的镜像文件,官方下载地址 3.导入刚刚下载的镜像(box文件) 4.初始化 5.修改Vagrantf ...

  10. 03 Django web服务开发 - URL路由

    Django中的APP -Django中的一个APP就是一个应用的意思 -项目可以包含多个APP(多个应用) -一个项目对应一个网站(生活服务网站) 一个APP队形网站的一个应用(二手交易,家政服务) ...