MyBatis批量插入/更新Oracle

Kev*_*vin 19 java sql oracle mybatis

我最近开始学习使用myBatis.我现在面临这样的情况,我需要不断通过WebService获取一个新的Objects列表,然后对于这个列表,我需要通过oracle DB表插入/更新每个对象MyBatis的.

棘手的部分是,我不能简单地每次都进行批量插入,因为某些对象可能已经存在于DB中,对于这些记录,我需要更新它们的字段而不是新的插入.

我当前的解决方案可能非常愚蠢,使用Java,从webservice构建Object列表,循环遍历每个,执行myBatis选择,如果它不是null(已经存在于db中),则执行myBatis更新; 否则,为这个新对象执行myBatis插入.

功能实现.但我的技术负责人表示它效率非常低,因为使用Java进行for循环并逐个插入/更新将消耗大量系统资源.他建议我通过传递一个对象列表来使用myBatis进行批量插入.

然而,myBatis中的批量插入很简单,因为我不是纯插入(对于我需要更新的现有记录),我不认为批量插入在这里是合适的.我已经google了一段时间,并意识到我可能需要使用"merge"而不是"insert"(对于Oracle).

我在myBatis中搜索合并的示例仅适用于一个对象,而不是批处理.因此,我想知道专家是否可以提供一些关于如何在MyBatis中进行批量合并的例子(编写Mapper的正确方法)?

rim*_*sky 32

接受的答案不是处理批处理操作的推荐方法.它不显示真正的批处理语句,因为在打开会话时应使用批处理执行程序模式.请参阅此帖子,其中代码撰稿人建议批量更新(或插入)的正确方法是以批处理模式打开会话并重复调用单个记录的更新(或插入).

这对我有用:

public void updateRecords(final List<GisObject> objectsToUpdate) {
    final SqlSession sqlSession = MyBatisUtils.getSqlSessionFactory().openSession(ExecutorType.BATCH);
    try {
        final GisObjectMapper mapper = sqlSession.getMapper(GisObjectMapper.class);
        for (final GisObject gisObject : objectsToUpdate) {
            mapper.updateRecord(gisObject);
        }
        sqlSession.commit();
    } finally {
        sqlSession.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

不要在更新/插入中使用foreach,并确保它只更新/插入单个记录.我根据接受的答案(无效字符,语句未结束等)进行了无法解决的oracle错误.正如链接的帖子所示,接受的答案中显示的更新(或插入)实际上只是一个巨大的sql语句.


Sam*_*azi 26

在我的情况下也有相同的情况.我用于循环检查这个记录是否存在于数据库中,然后根据我将此对象添加到两个arraylist中进行插入或更新.然后在for循环之后使用批处理插入和更新列表.

这是前.根据不同的条件进行更新

1]这是为了更新

<foreach collection="attendingUsrList" item="model"  separator=";">
    UPDATE parties SET attending_user_count = #{model.attending_count}
    WHERE  fb_party_id = #{model.eid}  
</foreach>
Run Code Online (Sandbox Code Playgroud)

2]这是插入

<insert id="insertAccountabilityUsers" parameterType="AccountabilityUsersModel" useGeneratedKeys="false">
    INSERT INTO accountability_users 
        (
            accountability_user_id, accountability_id, to_username,
            record_status, created_by, created_at, updated_by, updated_at
        ) 
    VALUES
    <foreach collection="usersList" item="model" separator=","> 
        (           
            #{model.accountabilityUserId}, #{model.accountabilityId}, #{model.toUsername}, 
            'A', #{model.createdBy}, #{model.createdAt}, #{model.updatedBy}, #{model.updatedAt}     
        )
    </foreach>
</insert>
Run Code Online (Sandbox Code Playgroud)

在dao方法中声明为

void insertAccountabilityUsers(@Param("usersList") List<AccountabilityUsersModel> usersList);
Run Code Online (Sandbox Code Playgroud)

更新

这是我的批处理会话代码

public static synchronized SqlSession getSqlBatchSession() {
    ConnectionBuilderAction connection = new ConnectionBuilderAction();
    sf = connection.getConnection();
    SqlSession session = sf.openSession(ExecutorType.BATCH);
    return session;
}

SqlSession session = ConnectionBuilderAction.getSqlSession(); 
Run Code Online (Sandbox Code Playgroud)

实际上我已经在这里给出了这个问题的完整例子

  • 这不是批量插入/更新,它是一个巨大的sql语句.请看这里https://github.com/mybatis/mybatis-3/issues/484 (5认同)
  • 提供的插入解决方案不适用于Oracle DB. (3认同)
  • 是但是如果列表大小为零,则不要调用insert或update方法,否则会引发语法错误. (2认同)
  • 对Oracle而言,无法以这种方式进行更新和插入. (2认同)