Пакетная вставка/обновление MyBatis для Oracle

Недавно я начал изучать использование myBatis. Теперь я сталкиваюсь с таким сценарием, мне нужно постоянно извлекать новый список объектов через WebService, а затем для этого списка мне нужно вставить/обновить каждый объект в оракуле Таблица DB через myBatis.

Сложная часть заключается в том, что я не могу просто выполнять пакетную вставку каждый раз, потому что некоторые из объектов могут уже существовать в БД, для этих записей мне нужно обновить поля из них вместо новой вставки.

Мое текущее решение может быть очень глупо, с использованием Java, построить список объектов из webservice, пропустить через каждый из них, сделать выбор myBatis, если он не является нулевым (уже существует в db), затем выполните обновление myBatis; в противном случае сделайте вкладку myBatis для этого нового объекта.

Достигнута функция. Но мой технический руководитель говорит, что он очень низкоэффективен, поскольку выполнение цикла for с использованием Java и вставка/обновление по одному потребует много системного ресурса. Он посоветовал мне делать пакетную вставку с помощью myBatis, передав список объектов.

Пакетная вставка в myBatis проста, однако, поскольку я не просто вставляю (для существующих записей мне нужно сделать обновление), я не думаю, что пакетная вставка здесь подходит. Я задумался об этом за некоторое время и понял, что мне нужно будет использовать "merge" вместо "insert" (для Oracle).

Примеры, которые я искал для слияния в myBatis, относятся только к одному объекту, а не к пакету. Таким образом, я хочу выяснить, могут ли эксперты предложить мне несколько примеров того, как выполнить пакетное слияние в MyBatis (правильный способ написать Mapper)?

Ответы

Ответ 1

В моем случае также есть такой же сценарий. Я использовал для цикла, чтобы проверить, существует ли эта запись в базе данных или нет, а затем в соответствии с этим я добавил этот объект в два массива для вставки или обновления. А затем использовал пакет для вставки и обновления после цикла для этого списка.

здесь бывший для обновления в соответствии с другим, где условие

1] это для обновления

<foreach collection="attendingUsrList" item="model"  separator=";">
    UPDATE parties SET attending_user_count = #{model.attending_count}
    WHERE  fb_party_id = #{model.eid}  
</foreach>

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>

В методе дао объявить как

void insertAccountabilityUsers(@Param("usersList") List<AccountabilityUsersModel> usersList);

Обновить

Вот мой код сеанса

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

SqlSession session = ConnectionBuilderAction.getSqlSession(); 

На самом деле я уже дал полный пример здесь по этому вопросу

Ответ 2

Принятый ответ не является рекомендуемым способом обработки пакетных операций. Он не показывает истинные пакетные инструкции, так как режим запуска партии должен использоваться при открытии сеанса. См. Этот пост, в котором разработчик кода рекомендовал, чтобы надлежащий способ пакетного обновления (или вставки) состоял в том, чтобы открыть сеанс в пакетном режиме и повторно вызвать обновление (или вставить) для одной записи.

Вот что работает для меня:

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();
    }
}

Не используйте foreach в своем обновлении/вставке и убедитесь, что он только обновляет/вставляет одну запись. Я столкнулся с неразрешимыми ошибками оракула, выполнив это в соответствии с принятым ответом (недопустимый символ, оператор не закончился и т.д.). Как указывает связанная почта, обновление (или вставка), показанное в принятом ответе, на самом деле является просто гигантским выражением sql.