NS系统_设备查询_分页部分失效问题解析
NS系统_设备查询_分页部分失效问题解析
背景交代
功能路径:[标记背景黄色为触发功能点或报错用户]
gggg系统
——设施设备-设施设备综合查询-设备综合查询
-设施设备维护-设备维护
——日常养护-维修养护-维修养护处理(新增_表单_维修对象类型[选设备],选择维修对象[弹出设备列表])
问题代码:FMDao - public void findSblist(DataPageGrid dg, SbssCommonSb sbssCommonSb){
...…省略无关内容
if(StringUtils.isNotBlank(dg.getSort())||StringUtils.isNotBlank(dg.getOrder())) {
sqlExceptSelect.append(" order by " + dg.getSort() + " "
+ dg.getOrder() + ", t.addtime desc ");
} else {
sqlExceptSelect.append(" order by t.addtime desc ");
}
...…省略无关内容
}
问题数据:
注:设备功能代码只有一套,不同用户有各自的设备数据,通过数据权限过滤数据(本例中涉及:NNN、TTT)
现象
设备维护-
NNN:
1~3页数据正常,第四页开始,数据不变化
TTT:
数据展示正常
分析
解析思路:
- 先判断数据问题?还是功能问题?
- 根据背景交代中的注,功能代码共用一套,先“排除”功能问题!
- 根据现象中的描述,可发现TTT分页功能正常,故TTT数据正常;同理猜测,NNN数据异常。经大致对比,NNN数据的addtime字段为空,而功能代码中排序字段就是它(当然通过代码中排序字段可直接推测出问题原因)。
- 有根据地猜测出问题原因(排序字段为空和字段内容相同的结果应该是一致的,结论是oracle 的 order by 后跟的字段如果唯一,且字段大部分内容相同,便会触发此现象),下面就开始采取方式验证或处理了;
- 验证方式比较简单,将排序字段更换成主键,问题解决。
解决方法
代码中排序字段添加主键保底(不考虑数据是否正确情况下,功能均可正常运行[提升系统容差能力])
if(StringUtils.isNotBlank(dg.getSort())||StringUtils.isNotBlank(dg.getOrder())) {
sqlExceptSelect.append(" order by " + dg.getSort() + " "
+ dg.getOrder() + ", t.addtime desc,t.id");
} else {
sqlExceptSelect.append(" order by t.addtime desc,t.id");
}
答疑
1、为什么NNNaddtime字段为空,而TTT或其他addtime字段均有值?
(1)TTT或其他的数据来源均通过系统生成(单条新增或批量导入[导入excel])
(2)NNN的数据是通过手工整理的excel数据,复制入库表的,addtime字段类型是TIMESTAMP(6),故在excel中此字段为空(那时批量导入功能还未开发,项目经理要求给出个临时处理方案)
2、为什么oracle order by 字段 值均相同 会引起分页部分失效的诡异事情?
(1)先来了解下oracle 实现分页的 sql 语句(3层select嵌套)
真实语句:
select *
from (select row_.*, rownum rownum_
from (select *
from AE_SBSS_COMMON_SB t
where 1 = 1
and mane like ?
and isdel = ?
and deptcode in
(select distinct (sd.range) as depcode
from sys_user su, sys_depart_user sdu, sys_depart sd
where su.id = sdu.userid
and sd.id = sdu.departid
and su.id = ?
union
select distinct (ydr.dataid) as depcode
from sys_user su,
sys_role sr,
sys_user_role sur,
yw_data_role ydr
where su.id = sur.userid
and sr.id = sur.roleid
and ydr.roleid = sr.id
and su.id = ?)
order by t.addtime desc) row_
where rownum <= 150) table_alias
where table_alias.rownum_ >= 141
去掉数据权限过滤:
select *
from (select row_.*, rownum rownum_
from (select *
from AE_SBSS_COMMON_SB t
where 1 = 1
and mane like ?
and isdel = ?
order by t.addtime desc) row_
where rownum <= 150) table_alias
where table_alias.rownum_ >= 141
(2)填入真实参数,更改分页参数看结果
select rownum_,table_alias.*
from (select row_.*, rownum rownum_
from (select *
from AE_SBSS_COMMON_SB t
where 1 = 1
and mane like 'NNN'
and isdel = '0'
order by t.addtime desc) row_
where rownum <= 110) table_alias
where table_alias.rownum_ >= 101
select rownum_,table_alias.*
from (select row_.*, rownum rownum_
from (select *
from AE_SBSS_COMMON_SB t
where 1 = 1
and mane like 'NNN'
and isdel = '0'
order by t.addtime desc) row_
where rownum <= 120) table_alias
where table_alias.rownum_ >= 111
看到结果了么?同样的id,rownum_变了。在拿这个字段做条件过滤,不诡异才怪呢。
至于为什么它会在这种情况下变化,这个就得问oracle,可能是bug,可能不是(某种其他机制),还有没有必要在一探究竟,在于你。
select rownum_,table_alias.*
from (select row_.*, rownum rownum_
from (select *
from AE_SBSS_COMMON_SB t
where 1 = 1
and mane like 'NNN'
and isdel = '0'
order by t.addtime desc) row_
where rownum <= 120) table_alias
where table_alias.rownum_ >= 101
select rownum_,table_alias.*
from (select row_.*, rownum rownum_
from (select *
from AE_SBSS_COMMON_SB t
where 1 = 1
and mane like 'NNN'
and isdel = '0'
order by t.addtime desc) row_
where rownum <= 140) table_alias
where table_alias.rownum_ >= 121
rownum是啥,自行科普吧。
更深入的原因解析,后续等还有必要深究时,再行补录。
参考:https://www.cnblogs.com/xuwl/articles/9177683.html