Пакетное обновление Jooq с записями в MySql

0

Каков правильный способ пакетного обновления с помощью JOOQ?

У меня есть следующее:

public void updateScores(Map<String, Integer> teamScores) {
    writeContext().transaction(config -> {
        DSLContext dslContext = DSL.using(config);
        dslContext.batchUpdate(Maps.transformEntries(teamScores, (id, score) -> {
            TeamScoresRecord record = new TeamScoresRecord();
            record.setTeamId(id);
            record.setScore(score);
            return record;
        }).values()).execute();
    });
}

ИЛИ ЖЕ

public void updateScores(Map<String, Integer> teamScores) {
    writeContext().transaction(config -> {
        DSLContext dslContext = DSL.using(config);
        dslContext.batchUpdate(
                dslContext.selectFrom(TEAM_SCORES)
                          .where(TEAM_SCORES.TEAM_ID.in(teamScores.keySet()))
                          .forUpdate()
                          .fetch()
                          .stream()
                          .peek(record -> record.setScore(teamScores.get(record.getTeamId())))
                          .collect(Collectors.toList())
        ).execute();
    });
}

Какой из них является рекомендуемым способом пакетного обновления?

  • 0
    Current; y Я обнаружил, что первый работает, а второй нет. Я имею в виду, что первый действительно обновляет строки, а второй нет, потому что после этого выборка производит те же строки, которые были там до обновления
  • 0
    Любопытно: почему вы используете peek() , а не map() во втором примере? Кроме того, насколько велики ваши карты?
Показать ещё 3 комментария
Теги:
java-8
batch-processing
jooq

1 ответ

2
Лучший ответ

Этот вопрос, очевидно, очень субъективен и нелегко ответить. Вот несколько замечаний:

  • Даже с использованием пакетного API в jOOQ вы запускаете множество индивидуальных запросов, что накладывает немалые накладные расходы клиент/сервер. Это может быть хорошо в вашем конкретном случае, но, как правило, неплохо подумать о переносе всей логики в базу данных, например, вставив вашу карту во временную таблицу, а затем слияние двух наборов данных с помощью объемного оператора UPDATE
  • Обе ваши партии могут вызвать взаимоблокировки в базе данных, если две конфликтующие партии обновляют одни и те же записи в другом порядке. Я не уверен, что это проблема в коде, но вы можете убедиться, что этого никогда не произойдет.
  • В первом подходе будет выполняться один меньше запросов (запрос SELECT, который может быть довольно дорогим, в зависимости от размера встроенного списка). Однако без предложения FOR UPDATE первый подход может иметь более высокий риск взаимоблокировки.
  • Первый подход потенциально может запускать больше операторов обновлений, чем необходимо, например, для ID значений, которые были удалены в то же время. Второй подход предотвращает это

Теперь я не знаю MySQL достаточно хорошо, чтобы узнать, может ли здесь быть более сложным оператором обновления, т.е. Утверждение типа:

UPDATE team_scores
SET score = CASE id
  WHEN :id1 THEN :score1
  WHEN :id2 THEN :score2
  WHEN :id3 THEN :score3
  ...
END
WHERE id IN (:id1, :id2, :id3, ...)

Возможно, вы можете сравнить этот подход и сравнить его с пакетной (или объединить его с пакетной обработкой, например, массовое обновление 10 строк и пакетное обновление всех этих массовых обновлений)

  • 0
    Я тестировал это с базой данных H2, потому что это то, что мы используем для тестирования, поэтому я не уверен, что это также работает с MySQL. Вы знаете способ проверить Jooq на произвольных БД?
  • 0
    База данных использует механизм InnoDB, который реализует блокировку на уровне строк, поэтому второй не должен вызывать блокировку всей таблицы. Я попробовал вторую версию еще раз, и она работает. Возможно, я раньше использовал неправильные таблицы. В любом случае, из того, что вы сказали, я вернусь к старому, потому что кажется, что у него наименьший потенциал
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню