javajpatestingjunithibernate-entitymanager

Nullified stored data


can you please explain me what i do wrong. I Am learning JPA and i'm stuck with tests. On the first test "teslaOne" i create and persist Entity to the db and i would like to get access to this data from second test "teslaTwo".

When i use Persistence.createEntityManagerFactory("h2database") it works but when i store it on the memoty Persistence.createEntityManagerFactory("in.memory.test") it does not.

i understand that "h2database" it is a fila, "in.memory.test" memory but it not clear for me why it have a different behavior and why it nullify data.

Can you tell me please how to share EntityManager between tests.

persistence.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             version="3.0"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
    <persistence-unit name="h2database" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.caveatemptor.core.data.entites.Tesla</class>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
            <property name="hibernate.connection.username" value="sa"/>
            <property name="hibernate.connection.password" value=""/>
            <property name="hibernate.connection.url" value="jdbc:h2:file:./h2data/demodb"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>

        </properties>
    </persistence-unit>

    <persistence-unit name="in.memory.test" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.caveatemptor.core.data.entites.Tesla</class>

        <exclude-unlisted-classes>false</exclude-unlisted-classes>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:h2:mem:"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="false"/>
        </properties>
    </persistence-unit>

</persistence>

Tesla.java

@Setter
@Getter
@ToString
@Entity()
public class Tesla implements Serializable {
    @Id
    @GeneratedValue
    protected Long ID;

    protected String vehicle;
}

TeslaTest.java

package com.caveatemptor.core.data.inheritance;

import com.caveatemptor.core.data.entites.Tesla;
import jakarta.persistence.*;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class TeslaTest {
//    private final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("h2database");
    private final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("in.memory.test");
    @Test
    void teslaOne(){
        Tesla tesla = new Tesla();
        tesla.setVehicle("Model X");

        EntityManager entityManager = entityManagerFactory.createEntityManager();

        EntityTransaction transaction = entityManager.getTransaction();

        try {
            transaction.begin();

            entityManager.persist(tesla);
            transaction.commit();

            Tesla teslaV = entityManager.find(Tesla.class, tesla.getID());
            assertEquals(teslaV.getVehicle(), "Model X");

        }
        finally {
            if(transaction.isActive()){
                transaction.rollback();
            }
            entityManager.close();
        }
    }


    @Test
    void teslaTwo(){
        EntityManager entityManager = entityManagerFactory.createEntityManager();

        EntityTransaction transaction = entityManager.getTransaction();

        try {
            transaction.begin();

            TypedQuery<Tesla> query = entityManager.createQuery("select t from Tesla t", Tesla.class);
            List<Tesla> items = query.getResultList();
            assertEquals(1, items.size());
        }
        finally {
            if(transaction.isActive()){
                transaction.rollback();
            }
            entityManager.close();
        }
    }

}


Solution

  • It makes sense that it’s not keeping the same in memory database as, without really knowing much about it, I assume it works much the same as objects and is stored in the heap. When you call createEntityManager() the second time, it’s like creating a new object and the reference points to the new object, leaving the old one to get cleaned up by the GarbageCollector.

    To prevent having to initialize the in memory database a second time, I believe setting it up as a @BeforeAll should do the trick.

    private final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("in.memory.test");
    private EntityManager entityManager;
    
    @BeforeAll
    void setup() {
        entityManager = entityManagerFactory.createEntityManager();
    }