【问题标题】:Add Oracle leading hint to HQL query向 HQL 查询添加 Oracle 前导提示
【发布时间】:2017-11-22 19:59:40
【问题描述】:

我想在我的 hql 查询中添加前导提示,但是,这个提示将像这样前导(别名),在休眠中我不知道 sql 中的别名是什么,我该怎么做?

 String hql="select s.id from " + StoreHouseInventoryItem.class.getName() + "s ,"+ Storehouse.class.getName() +" ss "

我想为这个查询添加前导提示,我不知道这 2 个表的休眠别名,前导需要别名。

hibernate 会生成这样的 sql:

select storeHouse0_.id  from app_item storeHouse0_ 
, app_str storeHouse1_

【问题讨论】:

  • 它有点不明白你的要求。你能详细说明一下吗
  • 我编辑问题
  • 值得一提的是,提示应该是一个临时的工作轮次,同时您要弄清楚是什么让 Oracle 优化器一开始就没有按照您的意愿行事。如果表上的统计数据发生变化,那么如果您有提示,Oracle 将无法轻松地使您的查询适应新的“人口统计”。

标签: java oracle hibernate oracle11g hql


【解决方案1】:

我做了以下,它对我有用:

  1. 创建了一个拦截器类

    public class HibernateEntityInterceptor extends EmptyInterceptor {
    
        private static final String HINT_START = "'$HINT-";
        private static final String HINT_END = "-$HINT',";
        private static final String ORACLE_HINT_START = "/*+ ";
        private static final String ORACLE_HINT_END = " */ ";
    
        @Override
        public String onPrepareStatement(String sql) {
    
            if (sql.contains(HINT_START)) {
                String hintText = StringUtils.substringBetween(sql, HINT_START, HINT_END);
                sql = StringUtils.replace(sql, HINT_START + hintText + HINT_END, ORACLE_HINT_START + hintText + ORACLE_HINT_END);
            }
            return sql;
        }
    
        public static String hint(String hint, boolean isEnabled) {
            return isEnabled ? HINT_START + hint + HINT_END : "";
        }
    }
    
  2. 在 HQL 中使用它,如下所示。这里我使用的是 "HASH_SJ" oracle 提示。

    String hql = "select " + HibernateEntityInterceptor.hint("HASH_SJ", true) + " 1 from tableEntityA";
    
  3. 注册拦截器

    jpaProperties.setProperty("hibernate.ejb.interceptor", "com.abc.HibernateEntityInterceptor");
    

【讨论】:

    【解决方案2】:

    字符串连接是一个非常严重的问题,可能导致SQL Injection attacks

    因此,由于您需要改变实体类型,因此您需要使用 Criteria API,它允许您使用 org.hibernate.comment 查询提示传递 SQL 提示,如下所示:

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
    Root employee = criteriaQuery.from(StoreHouseInventoryItem.class);
    Root address = criteriaQuery.from(Storehouse.class);
    criteriaQuery.multiselect(employee, address);
    Query query = entityManager
        .createQuery( criteriaQuery)
        .unwrap( org.hibernate.query.Query.class )
        .setComment( "leading(storehouseinventoryitem0_, storehouse1_)" );
    List<Object[]> result = query.getResultList();
    

    您还必须启用 SQL 级提示:

    <property
        name="hibernate.use_sql_comments"
        value="true"
    />
    

    更新

    至于知道别名,您只需运行查询并找出 Hibernate 为每个实体分配的别名,然后您应该在 Oracle 提示中使用这些别名。

    【讨论】:

    • 你怎么知道别名是 storehouseinvetpryitem0_,storehous1_ ??
    猜你喜欢
    • 2022-01-15
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多