惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
Martin Fowler
Martin Fowler
The GitHub Blog
The GitHub Blog
B
Blog RSS Feed
U
Unit 42
阮一峰的网络日志
阮一峰的网络日志
量子位
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
云风的 BLOG
云风的 BLOG
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
L
LangChain Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
IT之家
IT之家
V
Visual Studio Blog
Y
Y Combinator Blog
Blog — PlanetScale
Blog — PlanetScale
宝玉的分享
宝玉的分享
Apple Machine Learning Research
Apple Machine Learning Research
I
InfoQ
D
Docker
V
V2EX

博客园 - 试试手气

Web Worker 入门 若依Ruoyi分离版替换 MyBatis-Plus 若依前端菜单管理中路由地址、组件路径、权限字符的使用 Idea clone 项目推送到自有仓库 Spring Boot —— Spring Security Spring Boot —— 集成文档工具 Spring Boot —— Filter 过滤器 Spring Boot —— Cors 跨域 Spring Boot —— 集成 Druid Spring Boot —— 集成 MyBatis-Plus Spring Boot —— 集成 Springdoc Navicat 使用笔记 Datagrip连接SQLServer失败 Asp.net mvc 笔记 Asp.net Core 笔记 SQLServer 笔记 Asp.net Core 全局异常处理 SqlSugar 实践笔记 Asp.net Core 基于Cookie的身份认证
mybatis 笔记
试试手气 · 2023-06-16 · via 博客园 - 试试手气

不支持该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