码迷,mamicode.com
首页 > 其他好文 > 详细

MyBatisBatchItemWriter Cannot change the ExecutorType when there is an existing transaction

时间:2018-08-30 12:55:52      阅读:1134      评论:0      收藏:0      [点我收藏+]

标签:inf   sign   date   java   mybatis   values   connect   The   ESS   

但凡使用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

标签:inf   sign   date   java   mybatis   values   connect   The   ESS   

原文地址:https://www.cnblogs.com/nizuimeiabc1/p/9559461.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!