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

Spring JpaRepository自定义实现测试遇H2 Schema未找到问题

自定义JPA Repository实现类的测试问题

我通过@PersistenceContext注入EntityManager实现了自定义JPA Repository扩展类,因为要动态构建查询,没法使用仓库接口上的标准@Query注解。但用@DataJpaTest测试时,H2数据库报错找不到my_database schema;代码库中其他标准JpaRepository用同样方式测试都正常。我尝试在测试类中@Autowired EntityManager,再通过setter注入给new实例化的CustomFooDaoImpl,但仍出现H2提示找不到my_database Schema的异常。

相关代码

配置代码

public interface FooDao extends JpaRepository<Foo, Long>, CustomFooDao {}
public interface CustomFooDao {
    List<Foo> query();
}
public class CustomFooDaoImpl implements CustomFooDao {
    @PersistenceContext
    private EntityManager entityManager;

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public List<Foo> query() {
        return entityManager.createNativeQuery(someFancyQueryLiteral).getResultList();
    }
}

测试代码

@DataJpaTest
class CustomFooImplTest {
    @Autowired
    private EntityManager entityManager;

    private CustomFooDaoImpl customFooDaoImpl;

    @BeforeEach
    void setUp() {
        customFooDaoImpl = new CustomFooDaoImpl();
        customFooDaoImpl.setEntityManager(entityManager);
    }
}

异常信息

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Schema "my_database" not found; 
...

问题原因

你的原生SQL中硬编码了my_database这个schema名称,而H2测试数据库默认不会创建该schema,也不会自动切换到该schema下执行SQL。标准JpaRepository的方法使用JPQL,会自动适配测试环境的数据源,因此不会出现这个问题。

解决方法

方案1:测试配置中指定默认schema并自动创建

在src/test/resources/application.properties中添加H2配置,启动时自动创建并切换到目标schema:

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS my_database
spring.jpa.properties.hibernate.default_schema=my_database

方案2:测试类中手动创建schema

如果不想修改全局配置,可以在测试启动前手动执行创建schema的SQL:

@DataJpaTest
class CustomFooImplTest {
    @Autowired
    private EntityManager entityManager;
    private CustomFooDaoImpl customFooDaoImpl;

    @BeforeAll
    static void initSchema(@Autowired DataSource dataSource) {
        try (Connection conn = dataSource.getConnection()) {
            Statement stmt = conn.createStatement();
            stmt.execute("CREATE SCHEMA IF NOT EXISTS my_database");
            stmt.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @BeforeEach
    void setUp() {
        customFooDaoImpl = new CustomFooDaoImpl();
        customFooDaoImpl.setEntityManager(entityManager);
    }

    // 测试方法编写...
}

方案3:改造DAO,避免硬编码schema

将schema名称抽为配置项,适配不同环境:

  1. 在生产环境配置(src/main/resources/application.properties):
app.db.schema=my_database
  1. 在测试环境配置(src/test/resources/application.properties):
app.db.schema=PUBLIC
  1. 修改自定义DAO实现:
public class CustomFooDaoImpl implements CustomFooDao {
    @PersistenceContext
    private EntityManager entityManager;
    @Value("${app.db.schema}")
    private String dbSchema;

    public List<Foo> query() {
        String someFancyQueryLiteral = String.format("SELECT * FROM %s.foo WHERE ...", dbSchema);
        // 注意:如果要返回实体类,需要指定实体类型
        return entityManager.createNativeQuery(someFancyQueryLiteral, Foo.class).getResultList();
    }
}

方案4:直接注入完整的FooDao(推荐)

Spring Data JPA会自动代理实现FooDao接口,包含自定义扩展部分,无需手动实例化CustomFooDaoImpl:

@DataJpaTest
class CustomFooImplTest {
    @Autowired
    private FooDao fooDao;

    @Test
    void testQuery() {
        List<Foo> result = fooDao.query();
        // 编写断言逻辑
    }
}

结合方案1或3的schema配置,即可正常测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 01:45:27