mybatis-plus如何根据任意字段saveOrUpdateBatch

 更新时间:2025年09月01日 08:57:54   作者:孤海岛主  
MyBatisPlus saveOrUpdateBatch默认按主键判断操作类型,若需按其他唯一字段(如agentId、period、type组合)判断,需在service层重写方法,通过predicate定义插入条件并结合consumer执行更新逻辑,适用于批量和单条数据操作场景

使用场景

mybatisplus Iservice接口下的saveOrUpdateBatch方法默认是根据主键来决定是要更新还是插入的,

如果要根据其他字段(必须是唯一约束,唯一约束字段可以是多个)更新的话,则需要在项目的service层重写该方法。

方法源码

@Transactional(
        rollbackFor = {Exception.class}
    )
    public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
        TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass);
        Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]);
        String keyProperty = tableInfo.getKeyProperty();
        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]);
        return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> {
            Object idVal = ReflectionKit.getFieldValue(entity, keyProperty);
            return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession.selectList(this.getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
        }, (sqlSession, entity) -> {
            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap();
            param.put("et", entity);
            sqlSession.update(this.getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
        });
    }

从源码中可以看出实现saveOrUpdateBatch的主要方法就是SqlHelper.saveOrUpdateBatch

public static <E> boolean saveOrUpdateBatch(Class<?> entityClass, Class<?> mapper, Log log, Collection<E> list, int batchSize, BiPredicate<SqlSession, E> predicate, BiConsumer<SqlSession, E> consumer) {
        String sqlStatement = getSqlStatement(mapper, SqlMethod.INSERT_ONE);
        return executeBatch(entityClass, log, list, batchSize, (sqlSession, entity) -> {
            if (predicate.test(sqlSession, entity)) {
                sqlSession.insert(sqlStatement, entity);
            } else {
                consumer.accept(sqlSession, entity);
            }

        });
    }

该方法的最后两个参数predicate,consumer

predicate 这个函数是用于判断是否要进行插入操作 true插入,false:则通过consumer 函数执行更新

方法改造

注意:写在项目操作对应表的service层

首先在service层定义接口

boolean saveOrUpdateBatchByAgentIdAndPeriodAndType(List<Entity> list);

类为数据库表对应的实体类,agentId,period,type,这个三个字段为表的唯一约束,即当表中存在这三个字段组合对应的记录时则进行更新操作,不存在则进行插入操作

service层接口实现

@Transactional(rollbackFor = Exception.class)
    @DS("XXXX")//如果为多数据源,这里要指明具体操作的数据源名称
    public boolean saveOrUpdateBatchByAgentIdAndPeriodAndType(List<Entity> list) {

        return SqlHelper.saveOrUpdateBatch(entityClass, this.mapperClass, super.log, list, DEFAULT_BATCH_SIZE, (sqlSession, entity) -> {//这里主要是查询唯一约束对应的记录是否存在
            LambdaQueryWrapper<Entity> queryWrapper = Wrappers.<Entity>lambdaQuery()
                    .eq(Entity::getAgentId, entity.getAgentId()).eq(Entity::getPeriod,entity.getPeriod())
                    .eq(Entity::getType,entity.getType());
            Map<String, Object> map = CollectionUtils.newHashMapWithExpectedSize(1);
            map.put(Constants.WRAPPER, queryWrapper);
            return CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_LIST), map));
        }, (sqlSession, entity) -> {
            LambdaUpdateWrapper<Entity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.eq(Entity::getAgentId, entity.getAgentId()).eq(Entity::getPeriod,entity.getPeriod())
                    .eq(Entity::getType,entity.getType());
            Map<String, Object> param = CollectionUtils.newHashMapWithExpectedSize(2);
            param.put(Constants.ENTITY, entity);
            param.put(Constants.WRAPPER, lambdaUpdateWrapper);
            sqlSession.update(getSqlStatement(SqlMethod.UPDATE), param);
        });
    }

非批量的saveOrUpdate也可以按照这种方式进行改造

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java中三种常用布局方式小结

    Java中三种常用布局方式小结

    在Java Swing和JavaFX中,布局管理器(Layout Managers)用于控制组件(如按钮、文本框等)在容器(如窗口、面板等)内的位置和大小,下面介绍Java Swing中常用的三种布局方式,需要的朋友可以参考下
    2025-02-02
  • Java最长公共子序列示例源码

    Java最长公共子序列示例源码

    这篇文章主要介绍了Java最长公共子序列的定义及示例源代码,具有一定参考价值,需要的朋友可以看下。
    2017-09-09
  • java实现上传网络图片到微信临时素材

    java实现上传网络图片到微信临时素材

    这篇文章主要为大家详细介绍了java实现上传网络图片到微信临时素材,网络图片上传到微信服务器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • Java Springboot异步执行事件监听和处理实例

    Java Springboot异步执行事件监听和处理实例

    Java SpringBoot中,监听和处理事件是一种常见的模式,它允许不同的组件之间通过事件进行通信,事件监听和处理通常通过Spring的事件发布-订阅模型来实现,一个简单的Spring Boot应用程序示例,其中将包括事件的定义、事件的发布以及事件的监听
    2024-07-07
  • java实现选课系统

    java实现选课系统

    这篇文章主要为大家详细介绍了java实现选课系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • Java编程实现汉字按字母顺序排序的方法示例

    Java编程实现汉字按字母顺序排序的方法示例

    这篇文章主要介绍了Java编程实现汉字按字母顺序排序的方法,结合具体实例形式分析了java编码转换及字母排序相关操作技巧,需要的朋友可以参考下
    2017-07-07
  • Spring @Lookup深入分析实现原理

    Spring @Lookup深入分析实现原理

    这篇文章主要介绍了Spring @Lookup实现原理,我们知道在spring容器中单独的一个抽象类是不能成为一个bean的,那么有没有办法呢?这个时候我们可以使用Lookup注解
    2023-01-01
  • 线程池之newFixedThreadPool定长线程池的实例

    线程池之newFixedThreadPool定长线程池的实例

    这篇文章主要介绍了线程池之newFixedThreadPool定长线程池的实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • SpringBoot 配置文件总结

    SpringBoot 配置文件总结

    SpringBoot中提供一个全局的配置文件:application.properties,这个配置文件的作用就是,允许我们通过这个配置文件去修改Spring Boot自动配置的默认值,本文详细总结了SpringBoot配置文件,文中有详细的代码示例,感兴趣的同学可以参考下
    2023-05-05
  • IntelliJ IDEA2020.2.2创建Servlet方法及404问题

    IntelliJ IDEA2020.2.2创建Servlet方法及404问题

    这篇文章主要介绍了IntelliJ IDEA2020.2.2创建Servlet方法及404问题,这里小编使用的2020.2.2企业破解版本,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09

最新评论