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原生API实现文件夹复制,支持多级目录、空文件夹和文件覆盖等场景,并提供了基于File和FileChannel的实现方案,此外,还介绍了使用Java 7的Files工具类进行简化实现,需要的朋友可以参考下
    2026-01-01
  • Spring装配Bean之用Java代码安装配置bean详解

    Spring装配Bean之用Java代码安装配置bean详解

    这篇文章主要给大家介绍了关于Spring装配Bean之用Java代码安装配置bean的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。
    2017-10-10
  • 基于javamelody监控springboot项目过程详解

    基于javamelody监控springboot项目过程详解

    这篇文章主要介绍了基于javamelody监控springboot项目过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • SpringMVC实现全局异常处理器的经典案例

    SpringMVC实现全局异常处理器的经典案例

    文章介绍了如何使用@ControllerAdvice和相关注解实现SpringMVC的全局异常处理,通过统一的异常处理类和自定义业务异常类,可以将所有控制器的异常集中处理,并以JSON格式返回给前端,感兴趣的朋友一起看看吧
    2025-03-03
  • Java指令重排在多线程环境下的解决方式

    Java指令重排在多线程环境下的解决方式

    这篇文章介绍了Java指令重排在多线程环境下的解决方式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • 详解SpringBoot中META-INF的作用与功能

    详解SpringBoot中META-INF的作用与功能

    SpringBoot开发的应用程序中,META-INF目录扮演着非常重要的角色,本文就来介绍一下 META-INF的作用及用处,具有一定的参考价值,感兴趣的可以了解一下
    2025-07-07
  • SpringBoot + 微信公众号JSAPI支付功能的实现

    SpringBoot + 微信公众号JSAPI支付功能的实现

    这篇文章主要介绍了SpringBoot + 微信公众号JSAPI支付功能的实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • Spring Boot 访问安全之认证和鉴权详解

    Spring Boot 访问安全之认证和鉴权详解

    这篇文章主要介绍了Spring Boot 访问安全之认证和鉴权,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java判断字符串是否在List中的方案详解(忽略大小写)

    Java判断字符串是否在List中的方案详解(忽略大小写)

    对于需要频繁调用且数据量大的情况,有几种优化方案可以选择,下面给大家分享三种方案给大家详细介绍java字符串判断是否在list中,感兴趣的朋友一起看看吧
    2025-05-05
  • MyBatis-Plus联表查询及分页代码举例

    MyBatis-Plus联表查询及分页代码举例

    本文介绍了mybatis-plus-join工具的使用,该工具可以简化mybatis-plus的联表查询,使得开发者可以以类似QueryWrapper的方式进行联表查询,无需手动编写xml文件,感兴趣的朋友跟随小编一起看看吧
    2025-03-03

最新评论