使用本机查询但保持数据库独立性

时间:2015-11-02 10:51:44

标签: java spring jpa spring-data-jpa

使用Spring JPA有一种简单的方法可以使用本机查询但保持数据库独立性,例如使用最适合的查询?

目前我通过检查Dialect中当前设置的Environment来调用Repository的正确方法:

public Foo fetchFoo() {
    if (POSTGRES_DIALECT.equals(env.getRequiredProperty("hibernate.dialect"))) {
      return repo.postgresOptimizedGetFoo();
    }    
    return repo.getFoo();
}

这有效,但我觉得有一种更好的方法,或者我错过了一些东西。特别是因为(Spring)JPA允许它很容易地使用本机查询,但这打破了它的一大优势:数据库独立性。

3 个答案:

答案 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。