解决SqlServer自增主键使用MybatisPlus批量插入报错问题

报错

SqlServer 表中主键设置为自增,会报以下错误。

org.springframework.jdbc.UncategorizedSQLException: Error getting generated key or setting result to parameter object. Cause: com.microsoft.sqlserver.jdbc.SQLServerException: 必须执行该语句才能获得结果

报错原因

原因:mybatis-plus 批量执行时 SQL server 自增主键没有回填造成的。

从 MyBatis3.3.1 版本开始,MyBatis 开始支持批量新增回写主键值的功能,这个功能首先要求数据库主键值为自增类型,同时还要求该数据库提供的 JDBC 驱动可以支持返回批量插入的主键值(JDBC提供了接口,但并不是所有数据库都完美实现了该接口),因此到目前为止,可以完美支持该功能的仅有 MySQL 数据库。由于 SQL Server 数据库官方提供的 JDBC 只能返回最后一个插入数据的主键值,所以不能支持该功能。

分析

查看调用栈,来到 BatchExecutor 的 doFlushStatements 方法,执行了 jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects)

进入方法,在如图位置抛出异常

解决

实现工具类,给 MappedStatement 设置 NoKeyGenerator,问题就解决了

public class SqlUtil {
    /**
     * 500条数据 提交一次
     */
    private final static int BATCH_SIZE = 500;

    /**
     * 批量保存,解决 mybatis-plus 在批量插入时由于主键自增报错问题
     * 如果主键不是自增,不要调用
     * @param list     数据集合
     * @param mClazz   mapper
     * @return 操作结果
     */
    public static <E, M extends BaseMapper<E>> boolean saveBatch(Class<M> mClazz, List<E> list) {
        SqlSessionFactory factory = SpringUtil.getBean(SqlSessionFactory.class);
        SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false);
        MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(mClazz.getName() + ".insert");
        MetaObject metaObject = SystemMetaObject.forObject(ms);
        metaObject.setValue("keyGenerator", NoKeyGenerator.INSTANCE);
        M mapper = sqlSession.getMapper(mClazz);
        try {
            // 用于跟踪自上次刷新以来已处理的元素数
            int processedCount = 0;
            for (E e : list) {
                mapper.insert(e);
                processedCount++;
                if (processedCount >= BATCH_SIZE) {
                    sqlSession.flushStatements();
                    processedCount = 0;
                }
            }
            // 如果还有剩余的元素未刷新,则刷新
            if (processedCount > 0) {
                sqlSession.flushStatements();
            }
            sqlSession.commit();
            return true;
        } catch (Throwable t) {
            sqlSession.rollback();
            throw new RuntimeException(t.getMessage());
        } finally {
            SqlSessionUtils.closeSqlSession(sqlSession, factory);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鲁蛋儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值