← Назад к вопросам

Что сохранится в базу, если у Person вызвать persist или save и изменить возраст в транзакционном методе

2.0 Middle🔥 161 комментариев
#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Сохранение в базу при persist/save и изменении в транзакции

Этот вопрос касается поведения JPA/Hibernate при использовании методов persist() или Spring Data save() с последующим изменением атрибутов в транзакционном методе. Поведение зависит от того, находится ли объект в managed состоянии.

Различие между persist и save

EntityManager.persist()

  • JPA метод
  • Переводит объект в MANAGED состояние
  • Гарантирует INSERT в конце транзакции

Spring Data save()

  • Spring методl
  • Может быть как INSERT так и UPDATE
  • Также переводит объект в MANAGED состояние

Сценарий 1: Изменение после persist в одной транзакции

@Service
@Transactional
public class PersonService {
    @Autowired
    private EntityManager entityManager;
    
    public void createAndModifyPerson() {
        Person person = new Person();
        person.setName("John");
        person.setAge(25);
        
        // persist переводит объект в MANAGED состояние
        entityManager.persist(person);
        
        // Изменяем атрибут в ТОЙ ЖЕ транзакции
        person.setAge(26);
        
        // ЧТО СОХРАНИТСЯ В БД?
        // Ответ: age = 26
        // Причина: объект в MANAGED состоянии, Hibernate отслеживает изменения
    }
}

Результат в БД: age = 26

Причина: Объект находится в MANAGED состоянии (managed by persistence context). Hibernate отслеживает все изменения MANAGED объектов. При закрытии транзакции Hibernate автоматически генерирует UPDATE запрос.

Сценарий 2: Изменение после save в одной транзакции

@Service
@Transactional
public class PersonService {
    @Autowired
    private PersonRepository repository;  // Spring Data
    
    public void createAndModifyPerson() {
        Person person = new Person();
        person.setName("John");
        person.setAge(25);
        
        // save переводит объект в MANAGED состояние
        Person savedPerson = repository.save(person);
        
        // Изменяем атрибут
        savedPerson.setAge(26);
        
        // ЧТО СОХРАНИТСЯ В БД?
        // Ответ: age = 26
        // Причина: объект всё ещё MANAGED
    }
}

Результат в БД: age = 26

Сценарий 3: Изменение ВНЕ транзакции (отвязанный объект)

@Service
public class PersonService {
    @Autowired
    private PersonRepository repository;
    
    @Transactional
    public Person createPerson() {
        Person person = new Person();
        person.setName("John");
        person.setAge(25);
        return repository.save(person);
    }
    
    public void modifyPerson(Person person) {
        // person больше НЕ MANAGED (вышли из @Transactional метода)
        person.setAge(26);
        
        // БЕЗ сохранения - НИЧЕГО не будет в БД!
    }
}

Результат в БД: age = 25 (возраст не изменился)

Причина: Объект вышел из MANAGED состояния. Изменение атрибута не отслеживается.

Сценарий 4: Использование merge() для отвязанного объекта

@Service
public class PersonService {
    @Autowired
    private EntityManager entityManager;
    @Autowired
    private PersonRepository repository;
    
    public void modifyDetachedPerson(Person detachedPerson) {
        detachedPerson.setAge(26);
        
        // Нужно вернуть объект обратно в MANAGED состояние
        Person managedPerson = entityManager.merge(detachedPerson);
    }
    
    // Или через save (если вне транзакции)
    @Transactional
    public void updatePerson(Person person) {
        person.setAge(26);
        repository.save(person);  // Генерирует UPDATE
    }
}

Диаграмма состояний объекта

public class PersonLifecycleExample {
    // TRANSIENT -> новый объект, вне BD
    Person person = new Person();  // TRANSIENT
    
    // MANAGED -> отслеживается Hibernate
    entityManager.persist(person);  // MANAGED
    person.setAge(26);  // Изменение отслеживается
    // При коммите транзакции: UPDATE
    
    // DETACHED -> вышел из контекста
    // (после закрытия EntityManager или выхода из @Transactional)
    // Изменения НЕ отслеживаются
    
    // REMOVED -> удалён
    entityManager.remove(person);  // REMOVED
}

Практические советы

// Правильный способ: всё в одной транзакции
@Transactional
public void safePersist() {
    Person person = new Person();
    person.setName("John");
    repository.save(person);
    person.setAge(26);  // Автоматически сохранится
}

// Осторожно: разные транзакции
@Transactional
public Person createPerson() {
    Person person = new Person();
    return repository.save(person);
}

// Отвязанный объект - нужна явная сохранение
@Transactional
public void modifyDetached(Person person) {
    person.setAge(26);
    repository.save(person);  // Обязательно!
}

Ключевой вывод: Изменения MANAGED объектов в транзакции автоматически сохраняются. Изменения DETACHED объектов требуют явного вызова save() или merge().

Что сохранится в базу, если у Person вызвать persist или save и изменить возраст в транзакционном методе | PrepBro