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
}
Спасибо
Ответы
Ответ 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);