You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JPA测试中内存H2数据丢失及EntityManager共享问题咨询

JPA测试:内存H2数据丢失与EntityManager共享问题解析

一、内存H2测试间数据丢失的原因

H2内存数据库默认是会话私有实例:当使用jdbc:h2:mem:无名称的URL时,每个JDBC连接都会创建独立的内存库实例。JUnit的测试方法默认独立执行,第一个测试结束后,对应的连接关闭,内存库实例直接销毁;第二个测试拿到的是全新的内存库,自然读不到之前的数据。

而文件存储的H2(jdbc:h2:file:./h2data/demodb)是将数据持久化到磁盘,所有连接共享同一个文件实例,因此测试间数据能保留。

二、解决内存H2测试间数据共享的方法

修改内存H2的连接URL,指定数据库名称并添加DB_CLOSE_DELAY=-1参数:

<property name="hibernate.connection.url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1"/>
  • mem:testdb:指定内存库名称,让所有连接指向同一个实例
  • DB_CLOSE_DELAY=-1:禁止H2在最后一个连接关闭时销毁数据库,确保测试间实例不被回收

三、测试间共享EntityManager的正确方式

EntityManager本身线程不安全,不建议直接跨测试方法共享。更合理的是共享EntityManagerFactory,并通过JUnit生命周期注解控制资源:

优化后的测试类

package com.caveatemptor.core.data.inheritance;

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

import java.util.List;

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

public class TeslaTest {
    private static EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;

    @BeforeAll
    static void initFactory() {
        entityManagerFactory = Persistence.createEntityManagerFactory("in.memory.test");
    }

    @BeforeEach
    void initEntityManager() {
        entityManager = entityManagerFactory.createEntityManager();
    }

    @AfterEach
    void closeEntityManager() {
        if (entityManager.isOpen()) {
            entityManager.close();
        }
    }

    @AfterAll
    static void destroyFactory() {
        if (entityManagerFactory.isOpen()) {
            entityManagerFactory.close();
        }
    }

    @Test
    void teslaOne(){
        Tesla tesla = new Tesla();
        tesla.setVehicle("Model X");

        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();
            }
        }
    }

    @Test
    void teslaTwo(){
        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();
            }
        }
    }
}
  • @BeforeAll:全局初始化EntityManagerFactory,所有测试共享同一个工厂实例
  • @BeforeEach:每个测试前创建新的EntityManager,保证线程安全
  • @AfterEach:每个测试后关闭EntityManager,释放资源
  • @AfterAll:所有测试结束后销毁EntityManagerFactory

测试隔离可选方案

如果不需要测试间共享数据,可将hibernate.hbm2ddl.auto设为create-drop,让每个测试方法自动重建数据库:

<property name="hibernate.hbm2ddl.auto" value="create-drop"/>

内容的提问来源于stack exchange,提问作者Romillion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 02:38:14