Close

JPA - Detaching an Entity Instance from the Persistence Context

[Last Updated: Dec 1, 2017]

An entity becomes detached (unmanaged) on following actions:

  • after transaction commit/rollback
  • by calling EntityManager.detach(entity)
  • by clearing the persistence context with EntityManager.clear()
  • by closing an entity manager with EntityManager.close()
  • serializing or sending an entity remotely (pass by value).

Changes to a detached entity (changing fields, removing, refreshing etc) will not be synchronized to the database state.

A detached entity still has the database identity.

EntityManager.detach() method is cascaded to entities referenced by this entity if the attribute cascade=ALL or cascade=DETACH are used (check out cascading tutorial).

Example

The Entity

@Entity
public class Employee {
    @Id
    @GeneratedValue
    private long id;
    private String name;
    private String dept;
    .............
}

Persisting and loading

public class ExampleMain {

    public static void main(String[] args) throws Exception {
        EntityManagerFactory emf =
                Persistence.createEntityManagerFactory("example-unit");
        try {
            persistEntity(emf);
            loadEntity(emf);
        } finally {
            emf.close();
        }
    }

    private static void persistEntity(EntityManagerFactory emf) throws Exception {
        Employee e = new Employee();
        e.setName("Jackie");
        e.setDept("Account");
        System.out.println("-- Persisting entity --");
        System.out.println(e);
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        em.persist(e);
        e.setDept("Admin");
        //after commit entity will become detached
        em.getTransaction().commit();
        em.close();
        //this will not be synchronized to database
        e.setDept("IT");
    }

    private static void loadEntity(EntityManagerFactory emf) {
        System.out.println("-- Loading entities --");
        EntityManager em = emf.createEntityManager();
        List<Employee> entityAList = em.createQuery("Select t from Employee t")
                                       .getResultList();
        entityAList.forEach(System.out::println);
        em.close();
    }
}
-- Persisting entity --
Employee{id=0, name='Jackie', dept='Account'}
-- Loading entities --
Employee{id=1, name='Jackie', dept='Admin'}

As seen above, the changes which are made to Employee entity after the transaction commit, are not synchronized to the database.

Using detach() method

public class ExampleMain2 {

    public static void main(String[] args) throws Exception {
        EntityManagerFactory emf =
                Persistence.createEntityManagerFactory("example-unit");
        try {
            persistEntity(emf);
            loadEntity(emf);
        } finally {
            emf.close();
        }
    }

    private static void persistEntity(EntityManagerFactory emf) throws Exception {
        Employee e = new Employee();
        e.setName("Jackie");
        e.setDept("Account");
        System.out.println("-- Persisting entity --");
        System.out.println(e);

        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        em.persist(e);
        //need flush before detaching so changes made so far will
        //be synchronized to the database
        em.flush();
        //manually detaching
        em.detach(e);
        //this will not synchronized to the database
        e.setDept("Admin");
        em.getTransaction().commit();
        em.close();
    }

    private static void loadEntity(EntityManagerFactory emf) {
        System.out.println("-- Loading entities --");
        EntityManager em = emf.createEntityManager();
        List<Employee> entityAList = em.createQuery("Select t from Employee t")
                                       .getResultList();
        entityAList.forEach(System.out::println);
        em.close();
    }
}
-- Persisting entity --
Employee{id=0, name='Jackie', dept='Account'}
-- Loading entities --
Employee{id=1, name='Jackie', dept='Account'}

As seen above, changes made to Employee entity after invoking detach() are not synchronized to the database.

Example Project

Dependencies and Technologies Used:

  • hibernate-core 5.2.8.Final: The core O/RM functionality as provided by Hibernate.
    Implements javax.persistence:javax.persistence-api version 2.1
  • h2 1.4.193: H2 Database Engine.
  • JDK 1.8
  • Maven 3.3.9

EntityManager#detach() Example Select All Download
  • detach-entities-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • ExampleMain2.java
          • resources
            • META-INF

    See Also