文章目录

  • 特别声明
  • 问题
  • 业务分析
  • 解决方案
    • 方案1 循环更新
    • 方案2 拆分in表达式

特别声明

以下代码纯楼主手打,有错误地方还请谅解,看思路就行。

问题

在使用MybatisPlus过程中,报错ORA-01795 列表中的最大表达式数为1000

业务分析

我们由一个业务场景来慢慢引出最终的问题,根据某一种条件在数据库中的user表中查询到了3000条数据,然后对这些数据统一将状态state设置成1。此时我们会想到的sql语句如下,

update user_info set state=1 where id in (?,?,?,?.....)

由此我们使用MP的代码应该这么写,

//假设queryIdList方法是查询出符合条件的所有Id的集合,假设3000条数据
List<Long> ids = userService.queryIdList();
//更新这些id的状态
UserInfoEntity userUpdate = new UserInfoEntity();
userUpdate.setState(1);
this.update(userUpdate,new UpdateWrapper<UserInfoEntity>().in("id",ids));

这时候一执行,咔直接报了开头的错误,ORA-01795 列表中的最大表达式数为1000特别注意,MySQL数据库暂时还不会,阈值在哪个值我还目前没测。原因是这个报错信息也非常明确了,就是in的后面带的参数太多了,超过了1000条,因为我们是3000条

解决方案

因为超过了1000条,无可厚非,不管什么方案,我们先做的肯定都有一步,那就是把拿到的数据进行分组。这里楼主会用到一个很好用的工具类,分组代码也不用自己写了。只要加一个依赖com.google.guava

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>19.0</version>
</dependency>

分组方法

Lists类的partition方法

public static <T> List<List<T>> partition(List<T> list, int size) {Preconditions.checkNotNull(list);Preconditions.checkArgument(size > 0);return (List)(list instanceof RandomAccess ? new Lists.RandomAccessPartition(list, size) : new Lists.Partition(list, size));}
方案1 循环更新

既然是不许表达式数不能超过1000,那我就分组循环更新,代码如下。

//假设queryIdList方法是查询出符合条件的所有Id的集合,假设3000条数据
List<Long> ids = userService.queryIdList();
//对ids进行分组
List<List<Long>> partitionList=Lists.partition(ids,900);
partitionList.forEach(partition->{//更新这些id的状态UserInfoEntity userUpdate = new UserInfoEntity();userUpdate.setState(1);this.update(userUpdate,new UpdateWrapper<UserInfoEntity>().in("id",partition));
})
方案2 拆分in表达式

从sql语句表达式出发,我们可以尝试把in拆成多个in,用or来连接,因为or两边如果都是索引的话,索引是不会失效的。

update user_info set state=1 where id in (?,?,?,?.....)
--改造后
update user_info set state=1 where (id in (?,?,?)) or (id in (?,?,?)))
  • mapper.xml写法

    这个考验的是我们写Mapper.xml文件的时候的功底,是否灵活运用那几个常用标签。

    UserMapper接口

    void updateUserInfo(@Param("idss") List<List<Long>> idss);
    

    UserMapper.xml

    
    <update id="updateUserInfo">UPDATE user_info SET state = 1 WHERE<foreach collection="idss" open="(" close=")" separator="or" item="ids">id IN<foreach collection="ids" open="(" close=")" separator="," item="x">#{x}</foreach></foreach></update>
    

    从sql我们来分析一波,要想构造update user_info set state=1 where (id in (?,?,?) or (id in (?,?,?))),其实难点在(id in (?,?,?)) or (id in (?,?,?))),

    我们传入的参数是一个List<List>类型的,所以第一次循环的时候,起点是(,终点是),操作符应该是那个or,然后遍历的其实是每组里的List,这里我们取个名字叫做ids,

    然后内层循环解决的就是id in (?,?,?),这就是咋们平时熟悉的foreach了,我这就不多说了,这样说应该就能看懂上面为啥这么做了吧。至此,也就能实现分开in,避免表达式数超过1000。

  • 代码写法

    代码层面要使用lambda表达式写法,考验的大家的api使用熟练度,说实话楼主也是用到学,谁去天天记那么多,大不了多测几个demo嘛,大家别害怕。这里呢要用到的是QueryWrapperUpdateWrapperandor方法。

    default <T> boolean newUpdate(UserEntity userEntity, UpdateWrapper<UserEntity> wrapper, String column, List<T> ids) {if (CollectionUtils.isEmpty(idss)) {//判断传递进来的ids为空,为空则不进行ids的操作return this.update(userEntity, wrapper);} else if (ids.size() <= 1000) {//判断传递进来的ids长度是否小于等于1000,是则用正常的in方法wrapper.in(column, ids);return this.update(userEntity, wrapper);}else{//todo 关键解决问题的代码//代码走到这里,说明长度超过了1000,先进行分组List<List<T>> partitionList = Lists.partition(ids, 900);//进行 (id in (?,?,?) or (id in (?,?,?)))的构造queryWrapper.and(x -> {for (List<Long> idPartition : partitionList) {x.or(y -> y.in("id", idPartition));}});return this.update(userEntity,wrapper);}}
    

    特别注意,这段代码尤其lambda表达式那里要多写and、or方法的demo,你才会熟练。这里给出几个sql例子,自己尝试用QueryWrapper去构造,如果成功了,那么你就看得懂上面的代码了.

    --eg1
    select * from 表名 where name='张三' or name='李四'
    --eg2
    select * from 表名 where name='张三' and (age=11 or age=12)
    --eg3
    select * from 表名 where (name='张三' and address='福建') or (name='李四' and address='北京')
    --eg4
    select * from 表名 where (id in (1,2,3)) or (id in (1,3,4))
    

【MybatisPlus】ORA-01795 列表中的最大表达式数为1000相关推荐

  1. oracle 表达式1000,oracle环境下占用编号的方法报语法错误:ORA-01795: 列表中的最大表达式数为 1000...

    oracle 环境下,调用方法NumberCodeGenerateManager.OcuppyModelNumberCodesAfterSaved(ObjectID, modelID, ds)进行编号 ...

  2. 《转》IN 查询时出现ORA-01795:列表中的最大表达式数为1000

    问题描述: SQL进行IN查询时出现:java.sql.SQLException: ORA-01795: 列表中的最大表达式数为 1000 解决办法: 问题原因是:SQL进行IN查询时,IN中的数据量 ...

  3. ORA-01795: 列表中的最大表达式数为 1000

    1.美图 2.报错 ### Error querying database. Cause: java.sql.SQLSyntaxErrorException: ORA-01795: 列表中的最大表达式 ...

  4. ORA-01795: 列表中的最大表达式数为1000的解决方法

    ORA-01795: 列表中的最大表达式数为1000的解决方法 参考文章: (1)ORA-01795: 列表中的最大表达式数为1000的解决方法 (2)https://www.cnblogs.com/ ...

  5. 【Oracle报错】ORA-01795: 列表中的最大表达式数为 1000 问题解决(使用JDK8的 stream 实现)

    1. 问题说明 -- 类似这种 SQL SELECT * FROM tableName WHERE tableField IN ('','') 姑且不说这种 SQL 的效率和可优化和替代性,就当前问题 ...

  6. python统计列表中元素个数_python中计算一个列表中连续相同的元素个数方法

    python中计算一个列表中连续相同的元素个数方法 最简单的例子: a = [1,1,1,1,2,2,2,3,3,1,1,1,3] # 问:计算a中最多有几个连续的1 很明显,答案是4 如果用代码实现 ...

  7. 使用NetBeans Lambda支持在Java 8中使用Lambda表达式对列表进行排序

    作为JSR 335的一部分, Lambda表达式已从Java 8开始引入Java语言,这是Java语言的一个重大变化. 如果您想了解更多关于Lambda表达式以及JSR 335的信息,可以访问以下资源 ...

  8. 返回表达式列表中最小值least(exp1,exp2,exp3,……,expn)

    1 least(exp1,exp2,exp3,--,expn) 2 [功能]返回表达式列表中值最小的一个.如果表达式类型不同,会隐含转换为第一个表达式类型. 3 [参数]exp1--n,各类型表达式 ...

  9. 当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式

    当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式. 比如 select * from T_Employee where FNumber not in ( select top 5* ...

最新文章

  1. mysql int char连接_MySQL中int、char以及varchar的性能比较
  2. Java类的连接与初始化 (及2013阿里初始化笔试题解析)
  3. guns 最新开源框架企业版下载_优秀!Github上10个开源免费的后台控制面板你值得拥有!...
  4. DataGrip 连接 Hive
  5. FTP 500 OOPS
  6. python open写入_Python3 open() 函数详解 读取文件写入文件追加文件二进制文件
  7. 运行到手机_清理手机垃圾的三个方法,让手机恢复流畅运行
  8. 其他转成十进制,十进制转其他进制
  9. Erlang --- gen_server
  10. 2021-09-02AUC
  11. opencv4nodejs安装
  12. win10系统怎么查看密钥?
  13. 最新QQ坦白说消息查看发送者
  14. MySQL8下载安装卸载教程
  15. jadx工具windows下载
  16. 文本每三行合并成一行
  17. 乐固加固后windows下实现给apk签名
  18. 算法快学笔记(十三):狄克斯特拉(Dijkstra)算法原理与实现
  19. allegro如何等长走线
  20. 六十甲子日吉凶时辰对照表

热门文章

  1. ​一文梳理ICML 2022中图机器学习热点和趋势
  2. 看了360与金山网盾的争执,我有几点疑惑....
  3. 送给所有程序员的新年祝福新年愿望
  4. Unity游戏存档与读档
  5. ZIP压缩包解密解压密码
  6. Moodlens:一个基于表情符号的中文微博情感分析系统(A3, SIGKDD2012)
  7. 旁瓣对消原理_自适应旁瓣对消及其在通信对抗系统中的应用研究
  8. 温湿度系统(花葵、库房检测)
  9. MAC 输入摄氏度小技巧
  10. TikTok运营工具大全(必收藏)