mybatis 笔记

不支持该SQL转换成分页查询

发生场景是一次分页改造,将原来某方法中查询全部结果再在方法中手动分页获取部分结果的逻辑改造成使用startPage从数据库查询进行分页,伪代码逻辑如下:

public void foo(Entity entity){

startPage();
var list1 = myMapper.selectQuery(entity);

startPage();
var list2 = myMapper.selectQuery2(entity); // 该语句抛出不支持该SQL转换成分页查询异常
}

起初以为连续使用startPage造成错误,将selectQuery2改成selectQuery测试,顺利通过,证明连续使用startPage本身不会引起错误。经同事提醒,结合错误提示,分析是selectQuery2中定义的sql语句有问题,mybatis不支持把sql转换成分页查询。

经查,由于数据源是SqlServer,有链接服务器能力,因此selectQuery2中查询语句写成了[ip].[数据库].[架构].[视图]的方式,其在xml定义并在查询中使用了“特殊”sql和符号,由于myBatis无法对from中的语法进行正确分析解释,造成异常,sql定义如下:

<sql>
select DISTINCT *
FROM [19.XX.XX.XX].[数据库名].[dbo].[视图名]
</sql>

解决方法把from中的带中括号的定义想办法移除,比如使用多数据源方式定义新的Mapper直接去访问目标数据源,即可将sql改为如下:

<sql>
select DISTINCT *
FROM 视图名
</sql>

补充:由于没有测试,尚不确定mybatis到底是不支持[ip].[数据库].[架构].[视图]的写法,还是仅仅不支持中括号字符

查询结果被合并

mapper 中定义的 sql 查询结果有3条,但执行 mapper 接口方法返回的实体列表只有1条,数据数量不符。这有可能是由于 xml 中的定义的 resultMap 有缺陷,如没有明确的定义一个用作主键的列,这分两种情况分别说明。

// reusltMap 定义
<resultMap id="vo" type="ProjectCentersStatisticsVo">
<association property="entityA" javaType ="domain.entityA">
<id property="id" column="id" />
</association>
</resultMap>

<select id="selectSql" resultMap="vo">
select id, name from t where xxx
</select>

第一种,resultMap 的定义中没有任何 result 或列,有的是 associationcollection association 中有id定义,此时,不会出现该问题,sql语句中出现的唯一的id被映射到entityA中的id
第二种,resultMap中定义了一个result,但它并不是id或者它在sql查询结果中并不是唯一的,但此时mybatis会将其看作主键来使用,值相同的结果被合并留下最后一条,会造成问题发生。

<resultMap id="vo" type="ProjectCentersStatisticsVo">
<result property="name" column="name" />
<association property="entityA" javaType ="domain.entityA">
<id property="id" column="id" />
</association>
</resultMap>

在上例中,resultMap中定义了一个name列,mybatis在处理查询结果时会将其作为主键,name相同的记录(行)将替代上一个,直至留下最后一个name不同的行。例如查询结果有3条,其中两条nametom,一条namejerry,mybatis处理后将返回2条记录,最后一条tom和唯一的一条jerry
第三种,为了避免发生上述问题,人为明确的定义一个主键在resultMap中,默认名字是id,如下

<resultMap id="vo" type="ProjectCentersStatisticsVo">
<result property="pk" column="pk" />
<result property="name" column="name" />
<association property="entityA" javaType ="domain.entityA">
<id property="id" column="id" />
</association>
</resultMap>

<select id="selectSql" resultMap="vo">
select id, id pk, name from t where xxx
</select>

在上例中,通过给resultMap增加一个pk字段来表示主键,在sql中增加一个pk列并为了保证其值的唯一用真的id填充,这样的好处是原本查询结果中的id字段还能正确映射到entityA中的id

posted @ 2023-06-16 13:37  试试手气  阅读(11)  评论(0编辑  收藏  举报