Подтвердить что ты не робот

Spring JpaRepository - отсоединить и привязать объект

Я использую spring boot и hibernate через jpa. Я использую интерфейс JpaRepository для реализации своих репозиториев. Как со следующим UserRepository

public interface UserRepository extends JpaRepository<User, Long> {
}

Я хочу добиться следующих

  • Загрузите пользовательский объект.
  • Измените состояние объекта объекта, например. user.setName( "Foo" )
  • Выполняет вызов внешней системы webservice. Сохранить результат вызова в DB
  • Только при успешном ответе этого вызова webservice сохраните новое состояние пользователя в репозитории.

Все вышеописанные шаги не выполняются в одной транзакции, то есть внешний вызов службы не выполняется.

Когда я сохраняю результат работы webservice в базе данных через свой репозиторий, мои изменения в объекте пользователя также сохраняются. Согласно моему пониманию, это связано с потерей подстилающего контекста персистентности на шаге 3. После некоторых google, я думаю, что могу достичь своей цели, если я могу отделить свою пользовательскую сущность на первом шаге и снова подключить ее на шаге 4. Пожалуйста, подтвердите, правильно ли я понимаю и как я могу это достичь? В интерфейсе JpaRepository не существует способа отсоединить объект.

Ниже приведен код, иллюстрирующий

public void updateUser(int id, String name, int changeReqId){
    User mUser = userRepository.findOne(id); //1
    mUser.setName(name); //2

    ChangeRequest cr = changeRequestRepository.findOne(changeReqId);
    ChangeResponse rs = userWebService.updateDetails(mUser); //3

    if(rs.isAccepted()){
        userRepository.saveAndFlush(mUser); //4
    }

    cr.setResponseCode(rs.getCode());
    changeRequestRepository.saveAndFlush(cr); //this call also saves the changes at step 2
}

Спасибо

4b9b3361

Ответ 1

Если вы используете JPA 2.0, вы можете использовать EntityManager # detach() для отсоединения одного объекта от контекста persistence. Кроме того, Hibernate имеет Session # evict(), который выполняет ту же задачу.

Так как JpaRepository не предоставляет эту функциональность, вы можете добавить к ней пользовательскую реализацию, что-то вроде этого

public interface UserRepositoryCustom {
    ...
   void detachUser(User u);
    ...
}

public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
    ...
}

@Repository
public class UserRepositoryCustomImpl implements UserRepositoryCustom {
    ...
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void detachUser(User u) {
        entityManager.detach(u);
    }
    ...
}

Я не пробовал этот код, но вы должны иметь возможность заставить его работать. Вы даже можете попытаться удерживать EntityManager в своем классе обслуживания (где updateUser()) с помощью @PersistenceContext и избегать суеты добавления пользовательской реализации в репозиторий.

Ответ 2

entityManager.clear() отключит все объекты JPA, так что это может быть не подходящее решение во всех случаях, если у вас есть другие объекты, которые вы планируете поддерживать.

ясно

/**
 * Clear the persistence context, causing all managed
 * entities to become detached. Changes made to entities that
 * have not been flushed to the database will not be
 * persisted.
 */
public void clear();

entityManager.detach(entity); Удалить данный объект из контекста персистентности

открепление

/**
 * Remove the given entity from the persistence context, causing
 * a managed entity to become detached.  Unflushed changes made
 * to the entity if any (including removal of the entity),
 * will not be synchronized to the database.  Entities which
 * previously referenced the detached entity will continue to
 * reference it.
 * @param entity  entity instance
 * @throws IllegalArgumentException if the instance is not an
 *         entity
 * @since Java Persistence 2.0
 */
public void detach(Object entity);