MyBatisBatchItemWriter Cannot change the ExecutorType when there is an existing transaction

Posted ppjj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatisBatchItemWriter Cannot change the ExecutorType when there is an existing transaction相关的知识,希望对你有一定的参考价值。

但凡使用mybatis,同时与spring集成使用时,接下来要说的这个问题是躲不了的。众所周知,mybatis的SqlSessionFactory在获取一个SqlSession时使用默认Executor或必须要指定一个Executor,这样一来,在同一个SqlSession的生命周期中,要想切换Executor是不可能的,比如在一个复杂业务中:

sqlSession.insert("insertMainOrder", mainOrder); // -----(1)
for(OrderInfo childOrder : childOrderList){ // -----(2)
sqlSession.insert("insertChildOrder", childOrder);
}

如果sqlSession使用ExecutorType.SIMPLE open出来的话,(2)处如果是用Jdbc batch操作将是不可能的,当然(2)处如果你再新open一个ExecutorType.BATCH的新的SqlSession的话:A、如果整个业务在无事务环境下运行的话,则不会报错,但是底层会使用多个不同的Connection,浪费资源,最重要的是无法保持在同一个事务中。B、如果整个业务在一个事务中运行的话(如propagation=Propagation.REQUIRED),则会在mybatis-spring框架中报错:TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction"),也就是标题中的错误,究其原因是因为在mybatis-spring框架中在有事务情况下SqlSession是通过sessionFactory与当前线程绑定的,新open出来的SqlSession会与上一个使用的SqlSession的ExecutorType进行比较,如果ExecutorType改变了,则直接报错。

首先了解下相关知识,mybatis的执行器有三种类型:

  • ExecutorType.SIMPLE

这个类型不做特殊的事情,它只为每个语句创建一个PreparedStatement。

  • ExecutorType.REUSE

这种类型将重复使用PreparedStatements。

  • ExecutorType.BATCH

这个类型批量更新,性能更优,但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,这在某型情形下是不符合业务要求的。

使用方式:

java代码中,创建模板的时候:

new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
或者
SqlSession session = getSqlSessionFactory().openSession(ExecutorType.BATCH);

 

xml文件配置:

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">  
        <constructor-arg index="0" ref="sqlSessionFactory"/>  
        <constructor-arg index="1" value="BATCH"/>  
</bean>

 

下面是具体执行方法:

1,ExecutorType.SIMPLE:可以返回自增键,自增键会在事务提交后,自动设置到传入的user对象中,只需要在mapper文件中,增加属性: useGeneratedKeys="true" keyProperty="productId":

    <!-- 插入一个user -->
    <insert id="insertUser" parameterType="User"
        statementType="PREPARED" useGeneratedKeys="true" keyProperty="userId">
        INSERT
        INTO user (
        <include refid="userColumns" />
        , create_time,
        update_time)
        VALUES
        (#{email}, #{pwd},#{nickname},
        #{phone}, #{sign}, #{age},
        #{birthday},
        #{createTime},
        now())
    </insert>

 

2,ExecutorType.SIMPLE,借助foreach动态sql语句,使用Insert values(...),(...),(...) 的方式,这种方式无法取到自增键:

    <!-- 批量插入user -->
    <insert id="insertUsers" parameterType="map" useGeneratedKeys="true"
        keyProperty="userId">
        INSERT
        INTO user (
        <include refid="userColumns" />
        , create_time,
        update_time)
        VALUES
        <foreach collection="users" item="userCommand" index="index"
            separator=",">
            (#{userCommand.email},
            #{userCommand.pwd},#{userCommand.nickname},
            #{userCommand.phone},
            #{userCommand.sign}, #{userCommand.age},
            #{userCommand.birthday},
            #{userCommand.sex},
            #{userCommand.createTime},
            now())
        </foreach>
    </insert>

3,ExecutorType.BATCH,但是SqlSession的执行器类型一旦设置就无法动态修改,因为这个方法仍然需要包在事务中。所以如果在配置文件中设置了执行器为SIMPLE,当要使用BATCH执行器时,需要临时获取:

 SqlSession session = sqlSessionTemplate.getSqlSessionFactory()
                .openSession(ExecutorType.BATCH, false);
        try {
            UserDao batchUserDao = session.getMapper(UserDao.class);
 
            for (UserCommand user : users) {
                batchUserDao.insertUser(user);
            }
            session.commit();
            // 清理缓存,防止溢出
            session.clearCache();
 
            // 添加位置信息
            userLbsDao.insertUserLbses(users);
 
        } finally {
            session.close();
        }

4,ExecutorType.BATCH,全部改成batch模式。但是没有办法获取到自增的id。

 


以上是关于MyBatisBatchItemWriter Cannot change the ExecutorType when there is an existing transaction的主要内容,如果未能解决你的问题,请参考以下文章

请求头 x-ca-keyx-ca-noncex-ca-signature 加密分析第一篇

自建CA和公共CA有什么不同?

什么是CA安全体系,CA认证体系,C A 分别代表什么

【CA】关于ca-certificates

openssl ca(签署和自建CA)

ca证书助手怎么下载电脑版