Storing JPA Entities

Using Jakarta Persistence (JPA) You can store new entities in the database either explicitly by calling the persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to EntityManager.remove . method or implicitly through a cascade operation.

Explicit persist

The following code stores an Employee entity class instance in the database:

  Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher");
  em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().beginjakarta.persistence.EntityTransaction.begin()Start a resource transaction.();
  em.persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to   EntityManager.remove  .(employee);
  em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().commitjakarta.persistence.EntityTransaction.commit()Commit the current resource transaction, writing any unflushed changes to the database.();

The Employee instance is constructed as an ordinary Java object, and its initial state is New. An explicit call to persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to EntityManager.remove . associates the object with an owner EntityManagerjakarta.persistence.EntityManagerInterface used to interact with the persistence context., em, and changes its state to Managed. The new entity is stored in the database when the transaction is committed.

The persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to EntityManager.remove . method throws an IllegalArgumentException if the argument is not an entity class instance. Only entity class instances can be stored in the database independently. Objects of other persistable types can be stored in the database only as embedded objects in containing entities.

Because operations that modify the database require an active transaction, persist throws a TransactionRequiredExceptionjakarta.persistence.TransactionRequiredExceptionThrown by the persistence provider when a transaction is required but is not active. if it is called without an active transaction.

An EntityExistsExceptionjakarta.persistence.EntityExistsExceptionThrown by the persistence provider when EntityManager.persist is called and the entity already exists. is thrown if the database already contains another entity of the same type with the same primary key. The exception is thrown either by persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to EntityManager.remove ., if the existing entity is currently managed by the EntityManager, or by commitjakarta.persistence.EntityTransaction.commit()Commit the current resource transaction, writing any unflushed changes to the database..

Referenced embedded objects

The following code stores an Employee instance with a reference to an Address instance:

  Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher");
  Address address = new Address("Holland", "Ohio");
  employee.setAddress(address);
  em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().beginjakarta.persistence.EntityTransaction.begin()Start a resource transaction.();
  em.persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to   EntityManager.remove  .(employee);
  em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().commitjakarta.persistence.EntityTransaction.commit()Commit the current resource transaction, writing any unflushed changes to the database.();

Instances of persistable types other than entity classes are automatically stored as embedded objects in their containing entities. Therefore, if Address is an embeddable class, the Employee entity is automatically stored in the database with its Address instance as an embedded object.

Note that embedded objects cannot be shared by multiple entities. Each containing entity must have its own embedded objects.

Referenced entities


If, however, the Address class in the previous example is an entity class, the referenced Address instance is not automatically stored in the database with the referencing Employee instance.

To avoid a dangling reference in the database, an IllegalStateException is thrown on commit if a persisted entity references another entity that is not stored in the database at the end of the same transaction.

The application is responsible for ensuring that when an object is stored in the database, the entire closure of entities reachable from that object through persistent reference fields is also stored. You can do this either by explicitly persisting every reachable object or by setting up automatic cascading persist operations.

Cascading persist

Marking a reference field with CascadeTypejakarta.persistence.CascadeTypeDefines the set of cascadable operations that are propagated to the associated entity..PERSISTjakarta.persistence.CascadeType.PERSISTCascade the persist operation (or CascadeTypejakarta.persistence.CascadeTypeDefines the set of cascadable operations that are propagated to the associated entity..ALLjakarta.persistence.CascadeType.ALLCascade all operations, which includes PERSISTjakarta.persistence.CascadeType.PERSISTCascade the persist operation) indicates that persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to EntityManager.remove . operations are automatically cascaded to entities that are referenced by that field. A collection field can reference multiple entities.

@Entityjakarta.persistence.EntityDeclares that the annotated class is an entity.
class Employee {
     :
    @OneToOnejakarta.persistence.OneToOneSpecifies a single-valued association to another entity class that has one-to-one multiplicity.(cascadejakarta.persistence.OneToOne.cascade(Optional) The operations that must be cascaded to the target of the association.=CascadeTypejakarta.persistence.CascadeTypeDefines the set of cascadable operations that are propagated to the associated entity..PERSISTjakarta.persistence.CascadeType.PERSISTCascade the   persist   operation)
    private Address address;
     :
}

In the preceding example, the Employee entity class contains an address field that references an Address instance, which is another entity class. Because of the CascadeType.PERSIST setting, when an Employee instance is persisted, the operation is automatically cascaded to the referenced Address instance. The Address instance is then persisted without requiring a separate persist call. Cascading can continue recursively, for example, to entities that the Address object references.

Global cascading persist

Instead of specifying CascadeTypejakarta.persistence.CascadeTypeDefines the set of cascadable operations that are propagated to the associated entity..PERSISTjakarta.persistence.CascadeType.PERSISTCascade the persist operation for each relevant reference field, you can specify it globally for any persistent reference. You can do this either by setting the ObjectDB configuration or, in a JPA-portable way, by specifying the cascade-persist XML element in the XML mapping file:

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
 http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
   <persistence-unit-metadata>
     <persistence-unit-defaults>
       <cascade-persist/>
     </persistence-unit-defaults>
   </persistence-unit-metadata>
</entity-mappings>

The mapping file must be in the default location, META-INF/orm.xml, or in another location that is specified in the persistence unit definition in persistence.xml.

Batch store

Storing a large number of entities requires special consideration. You can use the clear and flush methods together to save memory during large transactions:

  em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().beginjakarta.persistence.EntityTransaction.begin()Start a resource transaction.();
  for (int i = 1; i <= 1000000; i++) {
      Point point = new Point(i, i);
      em.persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to   EntityManager.remove  .(point);
      if ((i % 10000) == 0) {
          em.flushjakarta.persistence.EntityManager.flush()Synchronize changes held in the persistence context to the underlying database.();
          em.clearjakarta.persistence.EntityManager.clear()Clear the persistence context, causing all managed entities to become detached.();
      }
  }
  em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().commitjakarta.persistence.EntityTransaction.commit()Commit the current resource transaction, writing any unflushed changes to the database.();

Managed entities consume more memory than ordinary, unmanaged Java objects. Therefore, holding 1,000,000 managed Point instances in the persistence context can consume too much memory. The preceding code example clears the persistence context after every 10,000 persist operations. Updates are flushed to the database before clearing; otherwise, they would be lost.

Updates sent to the database by using flushjakarta.persistence.EntityManager.flush()Synchronize changes held in the persistence context to the underlying database. are temporary and are visible only to the owner EntityManagerjakarta.persistence.EntityManagerInterface used to interact with the persistence context. until a commit. Without an explicit commitjakarta.persistence.EntityTransaction.commit()Commit the current resource transaction, writing any unflushed changes to the database., these updates are discarded. The combination of clearjakarta.persistence.EntityManager.clear()Clear the persistence context, causing all managed entities to become detached. and flushjakarta.persistence.EntityManager.flush()Synchronize changes held in the persistence context to the underlying database. moves temporary updates from memory to the database.

Note: Flushing updates to the database is also useful before you execute queries to get up-to-date results.

You can also store a large number of entities by using multiple transactions:

  em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().beginjakarta.persistence.EntityTransaction.begin()Start a resource transaction.();
  for (int i = 1; i <= 1000000; i++) {
      Point point = new Point(i, i);
      em.persistjakarta.persistence.EntityManager.persist(Object)Make a new entity instance managed and persistent, resulting in its insertion in the database when the persistence context is synchronized with the database, or make a removed entity managed, undoing the effect of a previous call to   EntityManager.remove  .(point);
      if ((i % 10000) == 0) {
          em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().commitjakarta.persistence.EntityTransaction.commit()Commit the current resource transaction, writing any unflushed changes to the database.();
          em.clearjakarta.persistence.EntityManager.clear()Clear the persistence context, causing all managed entities to become detached.();
          em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().beginjakarta.persistence.EntityTransaction.begin()Start a resource transaction.();
      }
  }
  em.getTransactionjakarta.persistence.EntityManager.getTransaction()Return the resource-level   EntityTransaction   object.().commitjakarta.persistence.EntityTransaction.commit()Commit the current resource transaction, writing any unflushed changes to the database.();

Splitting a batch store operation into multiple transactions is more efficient than using one transaction with multiple calls to the flush and clear methods. Therefore, using multiple transactions is preferred when possible.