目录
【Q】mybatis执行自定义sql时,在执行最后多出现了一个limit的原因及解决方法
【Q】java.sql.SQLException: Column count doesn't match value count at row 1
【Q】Result type doesn't match for Select id="xxx"
【Q】Could not autowire. No beans of ‘xxxMapper‘ type found
【Q】Could not autowire. No beans of ‘xxxMapper‘ type found
【Q】org.mybatis.spring.MyBatisSystemException
【Q】java.lang.IllegalArgumentException
【Q】org.apache.ibatis.builder.BuilderException
【Q】org.apache.ibatis.type.TypeException
【Q】org.apache.ibatis.builder.IncompleteElementException
【Q】org.apache.ibatis.reflection.ReflectionException
【Q】org.xml.sax.SAXParseException
【Q】org.springframework.core.NestedIOException
详细整理
【Q】mybatis执行自定义sql时,在执行最后多出现了一个limit的原因及解决方法
背景
在执行sql的时候,使用了自定义的分页, sql会自动拼接limit
但是项目中配置了springboot的分页插件,
只要自定义的sql中有pageSize和pageNum参数值,
就会在执行之后自动加上limit, 这样就造成了两个limit ,导致sql报错,
所以这种情况可以改个名字, 比如pSize和pNum, 这样拼接就行了
SELECT * FROM demo WHERE deleted = 0 ORDER BY id desc limit #{pNum}, #{pSize}
分析
在Java项目中,使用MyBatis进行数据库操作时,分页是一个常见的需求。MyBatis本身并不提供内置的分页功能,但可以通过第三方插件如MyBatis-Plus或PageHelper来实现。然而,当在Spring Boot项目中同时使用这些分页插件时,可能会遇到冲突,尤其是当自定义SQL和分页插件同时处理分页逻辑时。
下面是一些扩展的优化建议和解决方案,用于处理你提到的分页问题:
1. 重新命名参数
如果你已经在Spring Boot中启用了分页插件,并且你的自定义SQL也需要传递`pageNum`和`pageSize`参数,你可以考虑将这些参数重新命名以避免冲突。例如,你可以将它们命名为`offset`和`limit`,或者任何其他不会与分页插件冲突的名称。
2. 清理ThreadLocal
MyBatis-Plus和PageHelper都使用`ThreadLocal`来存储分页信息,这样可以确保分页信息是线程安全的。但是,如果线程被线程池重用,可能会导致分页信息没有被正确清理,从而引发问题。为了避免这种情况,你可以:
- 在适当的时候调用`PageHelper.clearPage()`来清理分页信息。这通常是在你的分页查询执行完毕之后。
- 确保在查询执行后立即使用分页结果,以避免分页信息在ThreadLocal中残留。
3. 禁用多余的分页插件
如果你的项目中同时启用了两个分页插件,最好是只保留一个。这样可以避免不必要的冲突和性能开销。你应该根据你的项目需求和团队偏好选择最适合的插件,并在项目中统一使用。
4. 使用拦截器检测多个`limit`语句
如果你想在项目中保持警惕,并在不小心启用了两个分页插件时能够及时发现,你可以实现一个MyBatis拦截器,用于检测SQL语句中是否包含多个`limit`子句。如果检测到这种情况,拦截器可以抛出异常,从而让你知道配置中存在问题。
5. 配置文件中的分页插件开关
在Spring Boot的配置文件(如`application.yml`或`application.properties`)中,你可以设置一个开关来启用或禁用分页插件。这样,你可以通过更改配置文件来轻松控制分页插件的行为,而不是修改代码。
6. 单独的分页逻辑
如果你确实需要在某些情况下使用自定义分页逻辑,可以将这部分逻辑封装到一个单独的服务或工具类中。这样,你可以在需要的时候调用这个服务,而不是依赖于自动的分页插件。
【Q】日期比较的错误操作
查不到数据写法
<sql id="WHERE_ORDER_TIME_BEGIN_AND_END">
<if test="orderTimeBegin != null">
<![CDATA[ and order_time >= #{orderTimeBegin,jdbcType=DATE}]]>
</if>
<if test="orderTimeEnd != null">
<![CDATA[ and order_time <= #{orderTimeEnd,jdbcType=DATE}]]>
</if>
</sql>
可以查到数据写法
<sql id="WHERE_ORDER_TIME_BEGIN_AND_END">
<if test="orderTimeBegin != null">
<![CDATA[ and order_time >= #{orderTimeBegin}]]>
</if>
<if test="orderTimeEnd != null">
<![CDATA[ and order_time <= #{orderTimeEnd}]]>
</if>
</sql>
问题原因
实际上:数据库中该字段的类型是:
【`order_time` datetime DEFAULT NULL COMMENT '下单时间',】
上面SQL的区别在于:
查不到是因为在拼接SQL时,取DAO层的值时,
在字段后面添加了jdbcType=DATE。导致无法查到
为什么会在后面指定jdbcType,及真正的错误?
- 因为使用一个插件自动生成SQL,里面都有这个东西,所以就直接用了。
最终错误原因:不是不能用jdbcType,而是我jdbcType映射的类型写错了。应用jdbcType=TIMESTAMP
。
关于jdbcType的使用:
DATE和DATETIME的区别。DATE表示一个日期,肯定是有问题的。
如果使用jdbcType=DATETIME:报错:No enum constant org.apache.ibatis.type.JdbcType.DATETIME
原因是MyBatis不支持DATETIME类型。实际上,对于MySQL的DATETIME,MyBatis中应该使用jdbcType=TIMESTAMP。
MyBatis支持的类型:
什么时候使用jdbcType?
查询官网时可以发现
其他情况,MyBatis大部分场景可以自动分析出来。实际上,myBatis没有说什么时候用什么时候不用,感觉都可以使用,不区分select或者insert等语句的。
各种报错
1、MyBatis和ORM的区别: mybatis属于半orm,因为sql语句需要自己写。mybatis 并没有将 java 对象与数据库关联起来,而是将 java 方法与 sql 语句关联起来
2、MyBatis实现分页:
Mysql数据库: limit, 需要自己处理分页逻辑
使用PageHelper插件
3、#{}, ${} :
#{} : 预编译处理, 传进来的数据会 加 单引号
${} : 字符串替换, 直接替换掉占位符, 为了防止 SQL 注入,能用 #{} 的不要去用 ${}
4、MyBatis接口绑定的几种方式
使用注解, 在接口的方法上面添加 @Select @Update等注解
使用xml文件,xml映射文件中的namespace对应的接口的全路径名。当SQL语句比较简单的时候,使用注解绑定就可以了,当SQL语句比较复杂的话,使用xml方式绑定,一般用xml方式绑定比较多
5、DAO不可以重载, 方法名对应的 mapper.xml 文件里的一个 id,这个与方法名对应,系统会根据 namespace+id 找到对应的方法对应。
6、Mybatis 可以映射枚举类。
7、MyBatis不同映射文件中的id可以重复
8、传递多个参数给mapper:
@Param
使用 java对象
【Q】java.sql.SQLException: Column count doesn't match value count at row 1
java.sql.SQLException: Column count doesn't match value count at row 1
java.sql.SQLException:列计数与第1行的值计数不匹配
PS:在插入数据时,插入的字段个数跟数据库表字段个数不一致
<insert id="insertBatch">
INSERT INTO xxx
(cert_exam_paper_id,position_id,level,question,correct_option,description,analysis,deleted)
VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.certExamPaperId},
#{item.positionId},
#{item.level},
#{item.question},
#{item.correctOption},
#{item.description},
#{item.analysis},
#{item.deleted}
)
</foreach>
</insert>
【Q】Result type doesn't match for Select id="xxx"
问题:dao层方法爆红线,提示:
Result type doesn't match for Select id="xxx"
解决方法
错误提示为结果类型与Select id =“xxx”不匹配,将ResultType的值改为方法里的String类型即可
【Q】Could not autowire. No beans of ‘xxxMapper‘ type found
Could not autowire. No beans of 'xxxMapper' type found。
无法自动装配。 找不到'xxxMapper'类型的bean。
解决方法:添加注解
1、@Service用于标注业务层组件
2、@Controller用于标注控制层组件(如struts中的action)
3、@Repository用于标注数据访问组件,即DAO组件,这是从spring2.0新增的一个注解,用于简化 Spring 的开发,实现数据访问
4、@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注,把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>。
@Repository
@Mapper
【Q】Could not autowire. No beans of ‘xxxMapper‘ type found
异常信息
SpringBoot+Mybatis框架,根据条件查询数据,发生异常
解决
1、原xml文件:
2、原mapper文件:
3、解决办法:在参数前加@Param标签
【Q】The server time zone value
The server time zone value
服务器时区值
serverTimezone=UTC
将url后面加上 ?serverTimezone=UTC就行
jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
`serverTimezone=UTC` 是一个在数据库连接字符串中常见的参数,特别是在配置JDBC连接MySQL或其他数据库时。这个参数指定了服务器的时区,通常用于确保时间戳的正确处理。UTC代表协调世界时(Coordinated Universal Time),是一种世界时间标准。
当你在JDBC URL中设置`serverTimezone=UTC`时,你告诉JDBC驱动程序应该如何转换数据库服务器上存储的时间戳值。这是因为数据库服务器和客户端应用程序可能位于不同的时区,如果不明确指定时区,那么时间戳可能会因为时区差异而出现错误的解释。
例如,在MySQL JDBC连接字符串中,
jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
这样配置后,无论数据库服务器的实际时区是什么,JDBC驱动程序都会假设服务器上的时间戳是UTC时区的。然后,它会基于这个假设将时间戳转换为应用程序所在时区的本地时间。
如果不设置这个参数,当数据库服务器和客户端应用程序在不同的时区时,可能会出现以下问题:
- 时间戳可能会被错误地转换,导致应用程序看到的时间与存储在数据库中的实际时间不一致。
- JDBC驱动程序可能会抛出异常,指出它无法正确地确定或转换时区。
因此,设置`serverTimezone=UTC`是确保时间数据一致性的一种常见做法,特别是在分布式系统和全球化应用程序中。
serverTimezone=GMT%2B8
`serverTimezone=GMT%2B8` 是一个数据库连接字符串参数,用于指定数据库服务器的时区。在这个例子中,`GMT%2B8` 表示格林威治标准时间(GMT)加上8个小时的时区。URL编码中,`%2B` 是加号(`+`)的编码形式,因为在URL中直接使用加号可能会被解释为一个空格。
当你在JDBC URL中包含`serverTimezone=GMT%2B8`时,你告诉JDBC驱动程序应该按照GMT+8的时区来处理数据库服务器上的时间戳。这对于确保客户端应用程序正确解释存储在数据库中的时间戳非常重要。
例如,如果你的数据库服务器位于中国,那么可以在MySQL JDBC连接字符串中设置如下:
jdbc:mysql://hostname:port/databaseName?serverTimezone=GMT%2B8
这表示无论客户端应用程序位于世界的哪个地方,它都会假设数据库服务器上的时间戳是按照GMT+8时区(即中国标准时间)来存储的,并据此进行相应的转换。
如果不设置这个参数,那么当数据库服务器和客户端应用程序在不同的时区时,可能会出现时间戳不一致的问题。例如,客户端可能会看到比实际存储在数据库中的时间早或晚8个小时的时间戳。通过明确指定时区,可以避免这种类型的错误,并确保在全球分布式系统中时间数据的一致性。
【Q】org.mybatis.spring.MyBatisSystemException
找不到类中的 get 属性
org.mybatis.spring.MyBatisSystemException:
nested exception is org.apache.ibatis.reflection.ReflectionException:
There is no getter for property named 'userName' in 'class com.Xxxx'
org.mybati.spring.MyBatisSystemException:
嵌套异常为org.apache.ibatis.reflection.ReflectionException:
“class com.Xxxx”中名为“userName”的属性没有getter
检查取值表达式中的属性名是否写错了,例如:{username,jdbcType=INTEGER}把 userName 写成了 username
【Q】java.lang.IllegalArgumentException
因为 mybatis 的代码生成插件,xml 文件是追加,如果你执行了两次生成的话,表的映射 xml 里的代码会生成两遍,所以就会报错
BaseResultMap 重复了
Error parsing Mapper XML.
Cause: java.lang.IllegalArgumentException:
Result Maps collection already contains value for com.news.dao.SysLogMapper.BaseResultMap
分析映射器XML时出错。
原因:java.lang.IllegalArgumentException:
Result Maps集合已包含
com.news.dao.SysLogMapper.BaseResultMap的值
检查对应的 xml 文件中是否有两个相同的 BaseResultMap 结果集
【Q】org.apache.ibatis.builder.BuilderException
jdbcType 写错了
Cause: org.apache.ibatis.builder.BuilderException:
Error resolving JdbcType.
Cause: java.lang.IllegalArgumentException:
No enum constant org.apache.ibatis.type.JdbcType.xxxxx
原因:org.apache.ibatis.builder.BuilderException:
解析JdbcType时出错。
原因:java.lang.IllegalArgumentException:
没有枚举常量org.apache.ibatis.type.JdbcType.xxxxx
- 检查 resultMap 节点中的 jdbcType 属性是否写错了,例如:jdbcType=”DECIMAL”
- 检查取值表达式中的 jdbcType 属性是否写错了,例如:#{userid,jdbcType=DECIMAL}
【Q】org.apache.ibatis.type.TypeException
类名写错了
Cause: org.apache.ibatis.type.TypeException:
Could not resolve type alias 'com.xxxx'.
Cause: java.lang.ClassNotFoundException:
Cannot find class: com.xxxx
原因:org.apache.ibatis.type.TypeException:
无法解析类型别名“com.xxxx”。
原因:java.lang.ClassNotFoundException:
找不到类:com.xxxx
检查配置文件中的 parameterType、或者 resultMap 节点中的 type 属性对应的类是否写错了。
【Q】org.apache.ibatis.builder.IncompleteElementException
结果集 ID 写错了
org.apache.ibatis.builder.IncompleteElementException:
Could not find result map com.news.dao.UserMapper.BaseResultMap
org.apache.ibatis.builder.IncompleteElementException:
找不到结果映射com.news.dao.UserMapper.BaseResultMap
【Q】org.apache.ibatis.reflection.ReflectionException
org.mybatis.spring.MyBatisSystemException:
nested exception is org.apache.ibatis.reflection.ReflectionException:
Could not set property 'userName' of 'class com.Xxxx' with value '25' Cause:
org.apache.ibatis.reflection.ReflectionException:
There is no setter for property named 'userName' in 'class com.q18idc.Xxxx'
org.mybati.spring.MyBatisSystemException:
嵌套异常为org.apache.ibatis.reflection.ReflectionException:
无法设置值为“25”的“class.com.Xxxx”的属性“userName”原因:
org.apache.ipatis.reflection.reflection exception:
“classcom.Xxxx”中名为“userName“的属性没有setter
检查 resultMap 节点中的,id 或者 result 节点中的 property 属性名是否写错了
【Q】org.xml.sax.SAXParseException
创建 MYBATIS 配置文件实例出错
Cause: org.xml.sax.SAXParseException;
lineNumber: 3; columnNumber: 53;
文档根元素 "mapper" 必须匹配 DOCTYPE 根 "con"。
这个问题引起的原因是 mybatis 的 mapper 配置文件的 DOCTYPE 有误,正确的应该是
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
【Q】org.springframework.core.NestedIOException
解析 MYBATIS 配置文件出错
[*.xml]: Invocation of init method failed;
nested exception is org.springframework.core.NestedIOException:
Failed to parse mapping resource: 'file [*.xml]';
nested exception is org.apache.ibatis.builder.BuilderException:
Error parsing Mapper XML.
[*.xml]:调用init方法失败;
嵌套异常为org.springframework.core.NestedIOException:
无法分析映射资源:“file[*.xml]”;
嵌套异常为org.apache.ibatis.builder.BuilderException:
分析映射器XML时出错。
检查配置文件
有用请点赞,养成良好习惯!
疑问、交流、鼓励请留言!