如何让 camel-jpa 使用不同于默认值的 schema?
结论
@Table(schema = "DIFFERENT_SCHEMA") 是为这个实体指定 schema 的正确方式。正常情况下,Hibernate 会使用显式声明的 schema;hibernate.default_schema=MY_SCHEMA 只为没有指定 schema 的映射提供默认值,不会覆盖有效的 @Table(schema = ...)。Hibernate 配置说明
这个 named query 不需要额外的 Camel schema 参数。先检查注解是否被正确识别,以及 Camel 使用的 EntityManagerFactory 是否加载了这份实体映射。现有代码和异常还不足以确定具体原因。
为什么 named query 仍然访问 MY_SCHEMA
这段查询使用的是 JPQL:
select m from MyEntity m where m.relevant = 1
MyEntity 是实体名称。Hibernate 会根据当前持久化单元中的实体映射,确定实际访问的表或视图及其 schema。
如果题中的 @Table 已正确加载,生成的 SQL 应包含:
from DIFFERENT_SCHEMA.V_MY_ENTITY
但日志显示:
from MY_SCHEMA.v_my_entity
运行时生成 SQL 所用的映射与预期不一致。可能的原因包括注解导入错误、XML 映射覆盖了注解、运行时加载了旧实体类,或 Camel 使用了另一套持久化配置。仅凭这条日志,还不能认定 Camel 会忽略实体上的 schema。
先检查实体注解和运行时映射
确认 @Table 的导入包
@Table 必须来自当前 JPA 提供者支持的 Persistence API,并与 @Entity 等注解使用一致的包。
使用 Jakarta Persistence 的项目,映射可以写成:
import jakarta.persistence.Entity;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.Table;
import org.hibernate.annotations.Immutable;
@Entity
@Table(name = "V_MY_ENTITY", schema = "DIFFERENT_SCHEMA")
@Immutable
@NamedQuery(
name = "MyEntity.findAllRelevant",
query = "select m from MyEntity m where m.relevant = 1"
)
public class MyEntity {
// 保留原有的主键、字段及其他映射
}
使用旧版 Java Persistence API 的项目,应使用对应的 javax.persistence.*。不要为了修复这个问题就全部替换包名,也不要混用 javax.persistence 和 jakarta.persistence。Hibernate ORM 6 的迁移说明明确要求使用 jakarta.persistence.*。Hibernate ORM 6 迁移说明
还要检查是否误用了 Spring Data 等其他框架的同名 @Table 注解。
检查是否存在覆盖配置
检查当前持久化单元加载的 META-INF/orm.xml 及其他映射文件,确认:
- 是否为
MyEntity重新声明了表名和 schema。 - 是否使用了
metadata-complete或xml-mapping-metadata-complete,使相关注解被忽略。
JPA 允许 XML 映射覆盖注解,所以源码中的 @Table 不一定是最终生效的配置。Jakarta Persistence 映射规则
同时检查部署包中是否包含修改后的 MyEntity.class,以及依赖包中是否还有旧副本。如果配置了自定义 PhysicalNamingStrategy,也要检查它是否改写了 schema 名称。
明确指定 Camel 使用的 EntityManagerFactory
Spring Boot 的这项配置作用于接收它的 Hibernate EntityManagerFactory:
spring.jpa.properties.hibernate.default_schema=MY_SCHEMA
如果项目还手动创建了其他工厂,或存在多个持久化单元,就需要确认 Camel 实际使用的是哪一个。
Camel JPA 支持通过 entityManagerFactory 显式选择工厂。假设已正确配置的工厂以 entityManagerFactory 为名注册到 Camel Registry,可以这样指定:
.to("jpa://com.example.MyEntity"
+ "?namedQuery=MyEntity.findAllRelevant"
+ "&entityManagerFactory=#entityManagerFactory")
如果实际 bean 名称不同,替换成对应名称即可。引用的工厂必须管理 MyEntity,并加载正确的实体映射。Camel 官方也建议明确配置所用的 EntityManagerFactory,尤其是在有多个候选实例时。Camel JPA 配置说明
这项配置只负责选择工厂;如果工厂中的实体映射有误,仍需修正映射。
验证修复结果
保留原来的默认 schema:
spring.jpa.properties.hibernate.default_schema=MY_SCHEMA
同时保留 MyEntity 的显式映射:
@Table(name = "V_MY_ENTITY", schema = "DIFFERENT_SCHEMA")
重新构建并启动应用,让 EntityManagerFactory 重新加载映射,再检查实际 SQL,确认 V_MY_ENTITY 前面的限定符是否已变为 DIFFERENT_SCHEMA。
如果仍然使用 MY_SCHEMA,可以用 Camel 实际使用的同一个工厂创建 EntityManager,直接执行:
entityManager.createNamedQuery("MyEntity.findAllRelevant")
.getResultList();
如果直接调用也使用了错误的 schema,继续检查 Hibernate 映射和持久化单元配置。如果直接调用正确,则检查 Camel 端点绑定的工厂是否与验证时使用的一致。
单个实体跨 schema 查询不需要修改全局默认值。只有希望该工厂中所有未显式指定 schema 的映射都默认使用 DIFFERENT_SCHEMA 时,才应改为:
spring.jpa.properties.hibernate.default_schema=DIFFERENT_SCHEMA
注意 Oracle 的访问权限
SQL 使用了正确的 schema 后,数据库连接用户仍需有权查询目标对象。@Table(schema = ...) 只影响对象名称,不会切换登录用户或授予权限。
用应用实际连接的账号执行:
SELECT *
FROM DIFFERENT_SCHEMA.V_MY_ENTITY
WHERE 1 = 0;
如果仍报 ORA-00942,检查目标对象是否存在、连接的数据库是否正确,以及当前用户是否有查询权限。Oracle 的这个错误也可能表示对象存在,但用户无权访问。Oracle ORA-00942 说明
schema 应配置在实体映射中,不要把 JPQL 改成 from DIFFERENT_SCHEMA.MyEntity。@Immutable 控制 Hibernate 对实体修改的处理,不负责选择 schema。
备注:内容仅供参考。
