MyBatis的若干问题总结二

标签: Java 分类: Java 创建时间:2020-02-13 12:07:30 更新时间:2025-01-17 10:39:22

1.排序问题

这里的问题我其实是想ORDER BY后面的子句,传入一个动态的,比如可能是:ORDER BY RecordTime ASC,或者是ORDER BY SiteNo ASC,但是向下面的问题,就会出现错误。

1
2
3
4
5
6
7
8
SELECT * FROM lsmfhx.v_realtime WHERE SiteNo in
<foreach item="item" index="index" collection="SiteNos"
open="(" separator="," close=")">
#{item}
</foreach>
and parseDateTimeBestEffortOrNull(RecordTime) BETWEEN parseDateTimeBestEffortOrNull(#{startdate}) AND
parseDateTimeBestEffortOrNull(#{enddate}) AND MediumType = #{mediumtype} ORDER BY
#{order1} #{sort1} LIMIT #{page},#{size}

Syntax error: failed at position 343 (line 9, col 22): ‘ASC’ LIMIT 0,100 FORMAT TabSeparatedWithNamesAndTypes;

根据资料显示:

(1)对于形如#{variable} 的变量,Mybatis会将其视为字符串值,在变量替换成功后,缺省地给变量值加上引号。"variable"
(2)对于形如${variable}的变量,Mybatis会将其视作直接变量,即在变量替换成功后,不会再给其加上引号。

2.动态字段名

需求的含义是,我可以查询一个字段,也可能查询两个字段,比如:

1
2
3
4
## 查询一个字段
select name from table
## 查询两个字段
select name,age from table

一个语句中,我可能只查询姓名一个字段,而另一语句中我想查询姓名和年龄两个字段,如果单独写两个语句,我又觉得不合适,所以就有了动态字段的问题。
(1) 添加:statementType=”STATEMENT”

1
2
3
4
5
<select id="getChartArr" resultType="Map" statementType="STATEMENT">
SELECT ${fieldlist},RecordTime FROM lsmfhx.v_realtime where parseDateTimeBestEffortOrNull(RecordTime)
BETWEEN parseDateTimeBestEffortOrNull(${startdate}) AND
parseDateTimeBestEffortOrNull(${enddate}) AND MediumType = ${mediumtype} and SiteNo=${siteno}
</select>

(2) 将#{fieldlist}换为${fieldlist}

(3) 编写mapper

1
List<Map> getChartArr(String fieldlist,String startdate,String enddate,Integer mediumtype,Integer siteno);

(4) 在必要的时候给变量添加单引号,比如上面语句中的start_time和end_time

1
2
3
4
5
String filedlist="InsFlux,DifPress";

start_time="'"+start_time+"'";
end_time="'"+end_time+"'";
List<Map> history=vRealTimeMapper.getChartArr(filedlist,start_time,end_time,medium_id,sitelist);

因为最后编译成的sql语句类似如下内容

1
2
3
SELECT InsFlux,DifPress,RecordTime FROM lsmfhx.v_realtime where parseDateTimeBestEffortOrNull(RecordTime)
BETWEEN parseDateTimeBestEffortOrNull('2019-01-01') AND
parseDateTimeBestEffortOrNull('2019-02-02') AND MediumType = 2 and SiteNo=1

如果不加单引号就会变成:

1
2
3
SELECT InsFlux,DifPress,RecordTime FROM lsmfhx.v_realtime where parseDateTimeBestEffortOrNull(RecordTime)
BETWEEN parseDateTimeBestEffortOrNull(2019-01-01) AND
parseDateTimeBestEffortOrNull(2019-02-02) AND MediumType = 2 and SiteNo=1

sql语句就不对了。

3.无法给带下划线的的属性赋值

在使用mybatis的时候,遇到了一个奇怪的问题,有些字段从数据库中取出都是null,但是数据库中明明是有值的,比如issue_time,比如class_type。当然也是不所有的内容都是空的,比如application_job就不是空的,后来呢。我想到了, class_type是int类型,但是application_job是VARCHAR类型,会不会是这个数据类型的问题呢?所以就有两种解决方法,通俗的方法一种是将带下划线的数据类型变成String类型或者是将下划线去掉,当然这也不是长久之计。

比如下面的sql语句,如果将结果转换成 List<Map<String,Object>> 数组,理论上每一个Map都应该包含五个属性 last_sum_flux、last_sum_heat、SumFlux、RecordTime、SiteNo,但是结果却只有SumFlux、RecordTime和SiteNo这几个属性,我尝试修改了SiteNo改为Site,结果也还是一样,在返回的结果中有Site字段,却没有last_sum_flux字段和last_sum_heat字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<select id="getDailySumFlux" resultType="java.util.HashMap">
SELECT last_sum_flux,last_sum_heat,SumFlux,RecordDate as RecordTime,t.SiteNo as SiteNo
FROM (
SELECT recorddate as RecordDate,SiteNo,SumFlux,last_sum_flux,last_sum_heat
FROM daily d
WHERE RecordTime >='${startdate}'
AND RecordTime &lt;='${enddate}'
) AS t
INNER JOIN (
<foreach collection="site_list" item="item" index="index" separator="UNION ALL" >
SELECT #{item} AS SiteNo
</foreach>
) AS t2
ON t.SiteNo =t2.SiteNo
ORDER BY SiteNo,RecordDate
</select>

至于参考文章中的方法,还没有测试。而且就算是我修改了application的配置,似乎还是没有效果,无论我选择 map-underscore-to-camel-case 是 true 还是 false,都无济于事。奇怪的是,同样的代码,不同的数据库,竟然也会有差别,我就真是看不出来到底有什么区别了。

【解决方法】
经过尝试,我终于发现了两者的区别了,一个查询的为null,另外一个数据库查询的结果last_sum_flux不为null,所以就会出现差别。
1.关闭自动驼峰映射:

1
2
3
4
mybatis-plus:
configuration:
# 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似射
map-underscore-to-camel-case: false

2.配置属性,将null显示

1
2
3
4
5
6
mybatis-plus:
configuration:
# 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似射
map-underscore-to-camel-case: false
## 解决了值为null的字段不显示的问题
call-setters-on-nulls: true

我配置了call-setters-on-nulls,似乎不起作用,最后返回的结果Map<String,Object>,还是没有这个 last_sum_flux 字段。

参考文章:
1.mybatis无法给带有下划线属性赋值问题 开启 mapUnderscoreToCamelCase 自动驼峰命名
2.mybatis无法给带有下划线属性赋值问题
3.mybatis plus字段名称有下划线读取不到值的问题 map-underscore-to-camel-case: false # 数据库下划线自动转驼峰标示关闭
4.mybatis-plus返回map的一些问题 spring boot整合mybatis时,返回map中value为空导致字段不显示:mybatis-plus.configuration.map-underscore-to-camel-case=true
5.mybatis 数据库null值字段 无法映射到Map mybatis.configuration.call-setters-on-nulls=true
6.springboot+mybatis-plus接口返回map值为null的字段不显示
7.mybatis返回map类型数据空值字段不显示的解决方法
8.callSettersOnNulls 通俗的讲,即 MyBatis 在使用 resultMap 来映射查询结果中的列,如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段,这就导致在调用到该字段的时候由于没有映射,取不到而报空指针异常。

4. Cause: java.lang.IllegalArgumentException: argument type mismatch

使用到了Mybatis Plus,对于自增的字段,要使用type进行注释

1
2
3
4
public class Device {
@TableId(type = IdType.AUTO)
private Integer id;
}
参考文章:
1.mybatis 插件小bug

5.实体属性名和数据库字段名不一致时的处理

有时候如果实体属性中的字段名和数据库的字段名不一样,进行查询的时候,就会报错。

mybatis plus中有一个注解叫@Tablefield(exist = false),意思就是说,这个字段,数据库可以不存在,如果数据库不存在这个字段,不会报错,但是如果数据库中有这个字段,还会返回相应的信息吗?
经过实际的测试,添加了这个注解之后,即便是数据库中存在这个字段,那么相应的数据也不会返回了。

因为在使用 MyBatis Plus 返回相应的list()的时候,构造select语句,是使用的” select filed1,filed2 from table”这种形式,而不是”select * from table”的形式,所以需要自定义select语句

1
2
3
4
5
6
public interface MediumMapper extends BaseMapper<Medium> {

@Select("Select * from Medium")
List<Medium> findAll();
}

或者是在使用查询语句的时候,指定select语句

1
2
3
QueryWrapper<VClient> queryWrapper=new QueryWrapper<>(); // 查询条件
queryWrapper.select("*");
mapper.list(queryWrapper);
参考文章:
1.Mybatis 当实体属性与数据库字段不一致时的解决方案 (这篇文章其实还是有用的,就是说要采用resultMap的方式处理实体类和字数据库字段不一致的情况)
2.MyBatis之实体类属性与表字段不一致的处理
3.程序员,Mybatis 你踩过坑吗? (Mybatis的一些使用案例)
4.mybatis动态调用表名和字段名 (动态字段名,其实和我的需求有点像)
5.使用Mybatisplus中的selectMaps方法返回值字段为空不显示的问题 (这里有一个叫selectMaps的方法,可以自定义返回的字段,这里还提到了一个属性配置,就是call-setters-on-nulls,设置为true之后,即便数据库中的字段是null的,也会返回相应的字段)
6.java object互转Map的三种方法
7.MyBatis-Plus 自定义sql语句

6.Could not set parameters for mapping: ParameterMapping

7.invalid comparison: java.util.Date and java.lang.String

在使用若依自动生成的代码进行增加操作之后,出现了这个问题。本来我以为是数据类型的问题,把网上找的sql代码的数据类型,java中的Date类型,对应的数据库类型改为了datetime,之后还是不行。

【解决方法】
去掉为空的判断就可以了。

1
2
3
4
<!--错误-->
<if test="createTime != null and createTime != ''">create_time,</if>
<!--正确-->
<if test="createTime != null">create_time,</if>
参考文章:
1.mybatis异常invalid comparison: java.util.Date and java.lang.String 原工程中配置的是mybatis-3.2.8, 而我测试工程中用的是mybatis-3.3.0.后来在网上找了一下才知道, 原来这是mybatis 3.3.0中对于时间参数进行比较时的一个bug. 如果拿传入的时间类型参数与空字符串’’进行对比判断则会引发异常. 所以在上面的代码中去该该判断, 只保留非空判断就正常了。

8.Invalid value type for attribute ‘factoryBeanObjectType’: java.lang.String

这是在使用 mybatis 的时候出现的问题,因为我用了 mybatis-plus-boot-starter,所以他依赖的 底层的 mybatis 比较老。

【解决方案】
自行解决,或者将 mybatis-plus-boot-starter 改为 mybatis-plus-spring-boot3-starter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.4</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>

后来又遇到了 :“Bean named ‘ddlApplicationRunner’ is expected to be of type ‘org.springframework.boot.Runner’ but was actually of type ‘org.springframework.beans.factory.support.NullBean’”,只能通过 升级 mybatis-plus-boot-starter版本解决

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。