DataIntegrityViolationException: Error attempting to get column处理方案汇总

绝地灬酷狼 2023-09-30 13:23 75阅读 0赞

项目背景

项目整体采用的是springboot+mybatis 方式。有一次做数据查询的时候。console突然报:DataIntegrityViolationException: Error attempting to get column ‘xx’…异常。起初没在意。以为是xml中的SQL写错了,排查了没问题。百度一下这个报错,说是实体类属性与数据库字段类型不一致引起的,记录一下防止后续在遇到相似问题。

简单写一下出问题的xml及返回值类型:

1 mapper:

  1. <select id="getUserList" paramType="java.lang.Integer" resultType="com.rllc.pcloud.po.UserPo">
  2. select id,name,date,sign,del from sys_users where id=#{userId}
  3. </select>

2 UserPo:

  1. @Data
  2. public class UserPo{
  3. private Integer id;
  4. private String name;
  5. private String password;
  6. // 问题就出在这个有参构造方法中
  7. public UserPo(String id, String username, String password) {
  8. this.id = id;
  9. this.username = username;
  10. this.password = password;
  11. }
  12. }

问题就出在这个有参的构造方法中。而没有无参构造方法。没有无参构造函数时,mybatsi为啥报这个错误呢?此时只有一个包含全部属性的构造函数,mybatis就会找出这些属性对应的值,并实例化一个实体类对象。在找属性对应的值时,mybatis会按照实体类全属性的构造函数的入参顺序,与sql的查询结果对应,如果实体类的属性和sql结果列不能匹配时都会报错。

综上所述,问题定位了,就很好解决:

补上无参构造方法:

  1. public class UserPo{
  2. private Integer id;
  3. private String name;
  4. private String password;
  5. public UserPo(){
  6. }
  7. // 问题就出在这个有参构造方法中
  8. public UserPo(String id, String username, String password) {
  9. this.id = id;
  10. this.username = username;
  11. this.password = password;
  12. }
  13. }

OK了.

常见的原因汇总
1.封装集合中字段名与数据库列名不一致,检查是否一致以及是否有该字段;
2.使用lombok或是其他操作导致没有无参构造或是无get/set;
3.使用Druid,因为版本问题导致对于时间类型LocalDateTime.class处理异常;此种处理方案:不使用Druid或是使用其他数据库连接源进行替换或是Druid版本升级.
先说一下此异常的出处:
BaseTypeHandler.java中getResult

  1. public T getResult(ResultSet rs, String columnName) throws SQLException {
  2. try {
  3. // 结果集中对数据库字段与实体类属性进行映射处理
  4. return getNullableResult(rs, columnName);
  5. } catch (Exception e) {
  6. throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e);
  7. }
  8. }

此异常之前还会有异常,也就是说该异常会有多种原因导致,也就对应了该异常出现的解决方案会有多种.这里说一下第三种异常处理方案的处理定位处理过程.
问题场景描述
按照日期查询符合条件的课程记录信息,实体类中时间字段:startTime(格式为YYYY-MM-dd HH:mm:ss),数据库中字段start_time,字段类型dateTime.
堆栈异常信息(篇幅原因删减部分堆栈信息):

  1. org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'start_time' from result set. Cause: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'start_time' from result set. Cause: java.sql.SQLFeatureNotSupportedException
  2. at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147)
  3. Caused by: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'start_time' from result set. Cause: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'start_time' from result set. Cause: java.sql.SQLFeatureNotSupportedException
  4. at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:87)
  5. ... 73 more
  6. Caused by: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'start_time' from result set. Cause: java.sql.SQLFeatureNotSupportedException
  7. at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85)
  8. ... 99 more
  9. Caused by: java.sql.SQLFeatureNotSupportedException
  10. at com.alibaba.druid.pool.DruidPooledResultSet.getObject(DruidPooledResultSet.java:1771)
  11. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  12. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  13. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  14. at java.lang.reflect.Method.invoke(Method.java:498)
  15. at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69)
  16. at com.sun.proxy.$Proxy190.getObject(Unknown Source)
  17. at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38)
  18. at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28)
  19. at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85)
  20. ... 101 more

看堆栈信息,首先从最开始的位置开始看,很明显是LocalDateTimeTypeHandler.java中getNullableResult抛出的异常,最早出现的异常信息:java.sql.SQLFeatureNotSupportedException.
先看LocalDateTimeTypeHandler.java中getNullableResult

  1. public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
  2. return rs.getObject(columnName, LocalDateTime.class);
  3. }

rs.getObject有很多中实现方式,由于使用的是Druid数据库连接源(最初使用的版本是1.0.28),所以直接定位到DruidPooledResultSet.java中getObject:

  1. public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
  2. throw new SQLFeatureNotSupportedException();
  3. }

按照druid1.0.28翻看源码发现对于
关于日期类型处理说明LocalDateTime.class是不支持的,直接抛出SQLFeatureNotSupportedException.修改pom.xml中Druid版本,升级到1.2.1,然后看一下该版本的实现:

  1. public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
  2. try {
  3. return this.rs.getObject(columnLabel, type);
  4. } catch (Throwable var4) {
  5. throw this.checkException(var4);
  6. }
  7. }

说明高版本对LocalDateTime.class处理是支持的,重新测试之后正常!

说明:

  1. org.springframework.dao.DataIntegrityViolationException: Error attempting to get column 'createtime' from result set. Cause: java.sql.SQLDataException: Unsupported conversion from TIMESTAMP to java.lang.Byte
  2. ; Unsupported conversion from TIMESTAMP to java.lang.Byte; nested exception is java.sql.SQLDataException: Unsupported conversion from TIMESTAMP to java.lang.Byte
  3. at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:84)
  4. at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)

一个很简单的SQL查询,sql是没有问题。可是 一直报错。。问题出在@Data这注解上。spring

img

缘由:mybatis在 select * from table 而后映射到实体类的时候,会经过反射实例化,sql

在mybatis-3.5.0.jar 包中org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createByConstructorSignature(ResultSetWrapper, Class<?>, List

img

解决办法 :一、加上无参构造的注解。,或者本身写个无参构造函数,,mybatis在实例化对象的时候,(会选择第一个构造函数)mybatis

img

还有问题,就在无参构造函数上加上注解@AutomapConstructor 。。mybatis会选择带这个注解的构造函数

发表评论

表情:
评论列表 (有 0 条评论,75人围观)

还没有评论,来说两句吧...

相关阅读