Гибернация JPA обновление многопоточного единого объекта

#java #multithreading #hibernate #jpa #sql-update

#java #многопоточность #гибернация #jpa #sql-обновление

Вопрос:

У меня есть очередь сообщений, которая выдает сообщения с некоторой информацией об обновлении поля сущности. Существует 10 потоков, которые обрабатывают сообщения из очереди.

Например

  • 1-й поток обрабатывает сообщение, этот поток должен обновить поле A из моей сущности с идентификатором 123.
  • 2-й поток обрабатывает другое сообщение, этот поток должен одновременно обновить поле B из моей сущности с идентификатором 123.

Иногда после обновлений база данных не содержит некоторых обновленных полей.

какой-то механизм обновления:

 someService.updateEntityFieldA(entityId, newFieldValue);
  

какой-то сервис:

 public Optional<Entity> findById(String entityId) {
    return Optional.ofNullable(new DBWorker().findOne(Entity.class, entityId));
}

public void updateEntityFieldA(String entityId, String newFieldValue) {
    findById(entityId).ifPresent(entity -> {
        entity.setFieldA(newFieldValue);
        new DBWorker().update(entity);
    });
}
  

работник базы данных:

 public <T> T findOne(final Class<T> type, Serializable entityId) {
    T findObj;

    try (Session session = HibernateUtil.openSessionPostgres()) {
        findObj = session.get(type, entityId);
    } catch (Exception e) {
        throw new HibernateException("database error. "   e.getMessage(), e);
    }

    return findObj;
}

public void update(Object entity) {
    try (Session session = HibernateUtil.openSessionPostgres()) {
        session.beginTransaction();
        session.update(entity);
        session.getTransaction().commit();
    } catch (Exception e) {
        throw new HibernateException("database error. "   e.getMessage(), e);
    }
}
  

HibernateUtil.openSessionPostgres() получает каждый раз новый сеанс из

 sessionFactory.openSession()
  

Возможно ли выполнить такую логику без блокировок потоков / оптимистической блокировки и пессимистической блокировки?

Ответ №1:

Если вы используете sessionFactory.openSession() для того, чтобы всегда открывать новый сеанс, при обновлении hibernate может терять информацию о грязных полях, которые ему необходимо обновить, поэтому возникают проблемы и обновляются все поля.

Установка hibernate.show_sql свойства в true покажет вам инструкции SQL UPDATE , сгенерированные hibernate.

Попробуйте провести рефакторинг своего кода, чтобы в той же транзакции загрузить сущность и обновить поле. session.update Не требуется, поскольку сущность управляется, при фиксации транзакции hibernate удалит изменения и выпустит обновление SQL.