До настоящего момента синхронизация с базой данных осуществлялась во время фиксации. Менеджер сущностей является кэшем первого уровня, ожидающим фиксации транзакции, чтобы сбросить информацию в базу данных. Но что будет, если потребуется вставить Customer и Address?
tx.begin();
em.persist(customer);
em.persist(address);
tx.commit();
Всем ожидаемым изменениям требуется SQL-оператор. В данном случае два оператора insert генерируются и становятся постоянными, только когда происходит фиксация транзакции в базе данных. Для большинства приложений этой автоматической синхронизации данных будет достаточно. Хотя неизвестно, в какой именно момент времени поставщик на самом деле сбрасывает изменения в базу данных, вы можете быть уверены, что это случится, когда произойдет фиксация транзакции. База данных синхронизируется с сущностями в контексте постоянства, однако данные могут быть сброшены (flush) явным образом в базу либо сущности могут быть обновлены с использованием информации из базы (refresh). Если данные будут сброшены в базу данных в определенный момент, а позднее в коде приложение вызовет метод rollback(), то сброшенные данные будут изъяты из базы.
Сброс сущности. С помощью метода EntityManager.flush() поставщика постоянства можно явным образом заставить сбрасывать данные в базу, но не будет фиксации транзакции. Это позволяет разработчику вручную инициировать тот же самый процесс, который менеджер сущностей использует внутренне для сброса контекста постоянства.
tx.begin();
em.persist(customer);
em.flush();
em.persist(address);
tx.commit();
В приведенном коде можно отметить две любопытные вещи. Первая заключается в том, что em.flush() не станет дожидаться фиксации транзакции и заставит поставщика сбросить контекст постоянства. Оператор insert будет сгенерирован и выполнен при сбросе. Вторая вещь состоит в том, что этот код не будет работать из-за ограничения целостности. Без явного сброса менеджер сущностей станет кэшировать все изменения, а также упорядочивать и последовательно вносить их в базу данных. При явном сбросе будет выполнен оператор insert в отношении CUSTOMER, однако ограничение целостности в случае с внешним ключом ADDRESS окажется нарушено (столбец ADDRESS_FK в CUSTOMER). Это приведет к откату транзакции. Откат также произойдет в случае с уже сброшенными данными. Явные сбросы следует использовать осторожно и только при необходимости.
Обновление сущности. Метод refresh() применяется для синхронизации данных в направлении, противоположном сбросу, то есть он перезаписывает текущее состояние сущности, которая находится под управлением, с использованием данных в таком виде, в каком они присутствуют в базе данных. Типичный случай — когда вы используете метод EntityManager.refresh() для отмены изменений, внесенных в сущность только в памяти. Фрагмент варианта тестирования, который приведен в листинге 6.12, обеспечивает поиск Customer по идентификатору, изменение значения его firstName и отмену этого изменения с помощью метода refresh().
Customer customer = em.find(Customer.class, 1234L)
assertEquals(customer.getFirstName(), "Энтони");
customer.setFirstName("Уильям");
em.refresh(customer);
assertEquals(customer.getFirstName(), "Энтони");");
В контексте постоянства содержатся сущности, которые находятся под управлением. Используя интерфейс EntityManager, вы можете проверить, находится ли сущность под управлением, отсоединить ее или очистить контекст постоянства от всех сущностей.
Contains. Сущности либо управляются менеджером сущностей, либо нет. Метод EntityManager.contains() возвращает логическое значение и позволяет вам проверить, находится ли экземпляр определенной сущности в настоящее время под управлением менеджера в контексте постоянства. В варианте тестирования, приведенном в листинге 6.13, показано, что обеспечивается постоянство Customer, и вы можете незамедлительно проверить, находится ли эта сущность под управлением (em.contains(customer)). Ответ в данном случае звучит как «да». Далее происходит вызов метода remove() и сущность удаляется из базы данных, а также из контекста постоянства (em.contains(customer) возвращает false).
Customer customer = new Customer("Энтони", "Балла", "[email protected]");