使用Spring JPA有一种简单的方法可以使用本机查询但保持数据库独立性,例如使用最适合的查询?
目前我通过检查Dialect
中当前设置的Environment
来调用Repository
的正确方法:
public Foo fetchFoo() {
if (POSTGRES_DIALECT.equals(env.getRequiredProperty("hibernate.dialect"))) {
return repo.postgresOptimizedGetFoo();
}
return repo.getFoo();
}
这有效,但我觉得有一种更好的方法,或者我错过了一些东西。特别是因为(Spring)JPA允许它很容易地使用本机查询,但这打破了它的一大优势:数据库独立性。
答案 0 :(得分:2)
根据我的理解,这可以通过使用 @Transactional(readOnly = false)来实现,然后不是调用 session.createQuery ,而是可以使用 session.createSQLQuery ,如本例所示。 您的sql可以是您的任何本机查询。 希望这对你有用。 :)
@Override
@Transactional(readOnly = false)
public Long getSeqVal() {
Session session = entityManager.unwrap(Session.class);
String sql = "SELECT nextval('seqName')";
Query query = session.createSQLQuery(sql);
BigInteger big = (BigInteger) query.list().get(0);
return big.longValue();
}
答案 1 :(得分:1)
这只是一个想法:我不知道它是否有效:
我的想法是使用子接口,一个普通的Spring-Data-JPA接口,其中包含一个entiy的所有方法(没有本机查询提示)。我会为每个数据库创建一个子接口,“覆盖”特定于数据库的本机语句。 (如果没有特定于DB的语句,则此插入将为空)。然后我会尝试使用一些配置文件配置Spring-JPA以加载正确的特定接口(例如通过类名或包名称模式)
答案 2 :(得分:1)
这似乎是一种让查询工作变得复杂的方法。
如果您真的想使用优化查询,请至少为您的代码透明化。我建议使用命名查询并为每个数据库创建一个orm.xml
(很像Spring Boot用来为不同的数据库加载schema.xml
)。
在您的代码中,您只需执行
public interface YourRepository extends JpaRepository<YourEntity, Long> {
List<YourEntity> yourQueryMethod();
}
这将查找名为YourEntity.yourQueryMethod
的命名查询。现在在你的orm.xml
中添加命名查询(默认查询,在另一个中添加优化查询)。
然后,您需要配置LocalContainerEntityManagerFactory
以加载所需的特定内容。假设您有一个属性来定义您使用的数据库,请将其命名为database.type
,您可以执行以下操作
<bean class="LocalContainerEntityManagerFactoryBean">
<property name="mappingResources" value="classpath:META-INF/orm-${database.type}.xml" />
... other config ...
</bean>
这样,您可以保持代码清理if / then / else构造并在需要的地方应用。很好地清理您的代码imho。