Шаблон чтения / записи с использованием сервера java и ms sql - PullRequest
0 голосов
/ 06 марта 2020

У меня возникла проблема параллелизма при использовании сервера SQL и java. Я настроил очередь сообщений и установил систему для чтения из этой очереди. Вот что происходит с каждым сообщением:

  1. Сообщения содержат «количественный атрибут». Этот атрибут читается, и он обновляет строку в table1 с таким номером.
  2. Другая таблица, table2 содержит атрибут «total», а строка считывается, чтобы получить общее значение. Строки table1 и table2 могут быть отображены с использованием идентификатора.
  3. Строка table2 обновляется путем добавления количественного атрибута из сообщения.

Проблема заключается в том, что, когда у меня несколько экземпляров моего сервиса и оба экземпляра получают сообщение для обработки одной строки, они записывают разные значения в table2. Это своего рода шаблон чтения / записи.

Пример:

Я получил это в table2:

+------+-------+
| id   | total |
+------+-------+
| 1    | 100   |
+------+-------+
| 2    | 100   |
+------+-------+

и получил два сообщения для вставки двух строк в table1:

+------+-------+
| id   | qty   |
+------+-------+
| 1    | 10    |
+------+-------+

+------+-------+
| id   | qty   |
+------+-------+
| 1    | 50    |
+------+-------+

a) Сообщение 1 приходит и пытается обновить общее количество из таблицы 2, оно читает 100 и обновляет общее количество до 110 b) Сообщение 2 приходит и пытается обновить общее количество, так как первое сообщение не было завершено, оно также считывается как 100 и обновляется как 150. c) Мы ожидаем, что всего будет 160 (100 + 10 + 50), но мы получили 150, поэтому состояние неверное.

Есть что-нибудь Я могу использовать для решения этой проблемы параллелизма?

1 Ответ

0 голосов
/ 06 марта 2020

Итак, необходимо добавить блокировку в строке. Я предлагаю реализовать блокировку с двойной проверкой с использованием блокировок БД - https://en.wikipedia.org/wiki/Double-checked_locking).

1 - начать транзакцию (например, аннотацию @Transactional для вашего метода обслуживания)

2 - Извлечение сущности из базы данных в режиме блокировки PESSIMISTIC_WRITE (обязательно указывайте в спящем режиме, что копия fre sh должна считываться вместо копии, сохраненной в кеше сеанса)

3 - Выполнить изменение / обновление на поле

4 - Сохраните сущность (и убедитесь, что flu sh значение в БД, если вы не хотите ждать auto-flu sh)

5 - Зафиксируйте транзакцию (выполняется автоматически при использовании @Transactional)

Пока ваша транзакция блокирует строку целевого объекта / базы данных, предотвращая ее чтение другими транзакциями в процессе обновления.

Реализация выглядит следующим образом:

    @Transactional
    public void updateValue(int id) {
        final Session session = this.sessionFactory.getCurrentSession();
        final Table1 table = session.get(Table1.class, id,LockMode.PESSIMISTIC_WRITE);
        session.refresh(table);
        table.setCount(table.getNoteCount()+1);
        session.saveOrUpdate(table);
        session.flush();
    }

Надеюсь, это поможет.

...