如何得到hibernate显示在控制台的hql或sql语句?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何得到hibernate显示在控制台的hql或sql语句?相关的知识,希望对你有一定的参考价值。

参考技术A 如何得到hibernate显示在控制台的hql或sql语句?
找到hibernate的配置文件--
hibernate.cfg.xml
加入:
<property
name="hibernate.show_sql">true</property>
如果你用spring那么就要:
修改spring里面的配置文件:
...
<property
name="hibernateProperties">
<props>
<prop
key
=
"hibernate.dialect">org.hibernate.dialect.mysqlDialect</prop>
<prop
key
=
"hibernate.show_sql">false</prop>
...

Hibernate:如何使用 HQL 设置 NULL 查询参数值?

【中文标题】Hibernate:如何使用 HQL 设置 NULL 查询参数值?【英文标题】:Hibernate: How to set NULL query-parameter value with HQL? 【发布时间】:2010-01-23 14:21:00 【问题描述】:

如何将休眠参数设置为“null”?示例:

Query query = getSession().createQuery("from CountryDTO c where c.status = :status  and c.type =:type")
.setParameter("status", status, Hibernate.STRING)
.setParameter("type", type, Hibernate.STRING);

就我而言,状态字符串可以为空。我已经对此进行了调试,然后休眠然后生成一个像这样的 SQL 字符串/查询 ....status = null... 但是这在 MYSQL 中不起作用,因为正确的 SQL 语句必须是“status is null”(Mysql 不明白status=null 并将其评估为 false,因此根据我已阅读的 mysql 文档,不会为查询返回任何记录...)

我的问题:

    为什么Hibernate 不能将空字符串正确翻译为“is null”(而是错误地创建“=null”)?

    重写此查询以使其成为空值安全的最佳方法是什么?使用 nullsafe 我的意思是在“状态”字符串为空的情况下,它应该创建一个“为空”?

【问题讨论】:

对于那些对解决方案感兴趣的人,我认为 Criteria API 是一种方法。但是我仍然不太相信,因为它会可怕地加载代码并且使用 HQL 会更干净。也许真正的解决方案是实现你自己的 Hibernate 类型(我已经为 ENUM 实现了一个,但是这些自我实现的类型,至少基本的类型比使用 HQL 查询中的休眠类型中的 bulid 有很大的缺点(除非你还扩展了 HQL解析器?)是什么让这是一个巨大的项目,需要大量的 Hibernate 知识......(在第 2 部分继续) 刚刚也遇到了这个……天哪,这真是脑残。 我非常讨厌hibernate,这绝对是愚蠢的 这么多年过去了,有没有不使用 Criteria API 的解决方案? @phpslightly 我不敢相信还没有! 【参考方案1】:

    我相信 hibernate 首先将您的 HQL 查询转换为 SQL,然后才尝试绑定您的参数。这意味着它将无法将查询从param = ? 重写为param is null

    尝试使用 Criteria api:

    Criteria c = session.createCriteria(CountryDTO.class);
    c.add(Restrictions.eq("type", type));
    c.add(status == null ? Restrictions.isNull("status") : Restrictions.eq("status", status));
    List result = c.list();
    

【讨论】:

谢尔盖您好,感谢您的回答。我实际上也使用 Criteria API 实现了它(在您发布答案之前)。但我仍然认为这不是问题的“理想解决方案”。好吧,老实说,有时“奇怪/错误”没有真正好的解决方案....我已将您的答案标记为问题的“解决方案”。 不客气 :) 但是您对理想解决方案有何期望?如果您对标准 api 而不是 hql 感到满意,您可以随时为“null-safe”标准创建自己的工厂方法。 很好的答案!这个简单的修复帮助我查询一个可为空的字段,而无需求助于字符串构建查询!【参考方案2】:

这不是 Hibernate 特定的问题(它只是 SQL 的性质),是的,SQL 和 HQL 都有解决方案:

@Peter Lang 有正确的想法,并且您有正确的 HQL 查询。我猜你只需要一个新的干净运行来获取查询更改;-)

以下代码绝对有效,如果您将所有查询保存在 orm.xml 中,那就太好了

from CountryDTO c where ((:status is null and c.status is null) or c.status = :status) and c.type =:type

如果您的参数字符串为空,则查询将检查该行的状态是否也为空。否则会使用等号比较。

注意事项:

问题可能是特定的 MySql 怪癖。我只用 Oracle 测试过。

上述查询假设存在 c.status 为空的表行

where 子句有优先级,以便先检查参数。

参数名称“type”可能是 SQL 中的保留字,但无关紧要,因为它在查询运行之前被替换。

如果您需要完全跳过 :status where_clause;你可以这样编码:

from CountryDTO c where (:status is null or c.status = :status) and c.type =:type

相当于:

sql.append(" where ");
if(status != null)
  sql.append(" c.status = :status and ");

sql.append(" c.type =:type ");

【讨论】:

为什么不from CountryDTO c where (:status is not null and c.status = :status) and c.type =:type @Alex78191 使用or,查询将产生:from CountryDTO c where (true) and c.type =:type,而您的将产生:from CountryDTO c where (false) and c.type =:type,这将不会给您任何行。 @Alex78191 你也可以试试这个:select 'data' from dual where (1=2) 和这个:select 'data' from dual where (1=1) 看看有什么不同。【参考方案3】:

javadoc for setParameter(String, Object) 是显式的,表示 Object 值必须非空。遗憾的是,如果传入 null,它不会引发异常。

另一种选择是setParameter(String, Object, Type),它确实允许空值,虽然我不确定在这里哪个Type 参数最合适。

【讨论】:

你好,斯卡夫曼。非常感谢您的帮助!在问这个问题时,我实际上认为我只是愚蠢地寻找解决方案。但这似乎是hibernate的真正“怪事”。很可能我将不得不编写自己的 Nullable-String-Type 或者我将不得不切换到 Criteria Queries... 在深入挖掘之后,Hibernat.STRING 类型的当前实现似乎不可为空:docjar.com/html/api/org/hibernate/type/StringType.java.html。 (但 MySQL JConnector 不应该正确实现 PreparedStatment.setString 吗??)谢谢 Tim。 仅供参考,其实是JDBC的一个“特性”:bugs.sun.com/bugdatabase/view_bug.do?bug_id=4312435Hibernate使用JDBC的PreparedStatement.setNull()绑定null参数【参考方案4】:

您似乎必须在 HQL 中使用 is null,(如果有多个参数可能为空,这可能会导致复杂的排列。)但这是一个可能的解决方案:

String statusTerm = status==null ? "is null" : "= :status";
String typeTerm = type==null ? "is null" : "= :type";

Query query = getSession().createQuery("from CountryDTO c where c.status " + statusTerm + "  and c.type " + typeTerm);

if(status!=null)
    query.setParameter("status", status, Hibernate.STRING)



if(type!=null)
    query.setParameter("type", type, Hibernate.STRING)

【讨论】:

对我来说看起来像是旧的 sql 查询。坚持这样的标准api。手写 hql 极易出错。【参考方案5】:

HQL 支持 coalesce,允许使用以下丑陋的变通方法:

where coalesce(c.status, 'no-status') = coalesce(:status, 'no-status')

【讨论】:

【参考方案6】:

我没有尝试这个,但是当你使用:status 两次检查NULL 时会发生什么?

Query query = getSession().createQuery(
     "from CountryDTO c where ( c.status = :status OR ( c.status IS NULL AND :status IS NULL ) ) and c.type =:type"
)
.setParameter("status", status, Hibernate.STRING)
.setParameter("type", type, Hibernate.STRING);

【讨论】:

帮助彼得,非常感谢您的帮助!我不知道为什么,但似乎hibernate总是将(c.status = :status OR(c.status IS NULL AND :status IS NULL)评估为c.status = null(根据我的mysql查询日志)。我也将顺序更改为 (( c.status IS NULL AND :status IS NULL ) OR c.status = :status) ,结果相同。谢谢 Tim【参考方案7】:

对于实际的 HQL 查询:

FROM Users WHERE Name IS NULL

【讨论】:

【参考方案8】:

你可以使用

Restrictions.eqOrIsNull("status", status)

插入

status == null ? Restrictions.isNull("status") : Restrictions.eq("status", status)

【讨论】:

【参考方案9】:

这是我在 Hibernate 4.1.9 上找到的解决方案。我必须将一个参数传递给我的查询,该参数有时可以具有 NULL 值。所以我通过了使用:

setParameter("orderItemId", orderItemId, new LongType())

之后,我在查询中使用以下 where 子句:

where ((:orderItemId is null) OR (orderItem.id != :orderItemId))

如您所见,我使用的是 Query.setParameter(String, Object, Type) 方法,我无法使用在文档中找到的 Hibernate.LONG(可能是在旧版本上)。 type参数的全套选项请查看org.hibernate.type.Type接口的实现类列表。

希望这会有所帮助!

【讨论】:

【参考方案10】:

这似乎也有效 ->

@Override
public List<SomeObject> findAllForThisSpecificThing(String thing) 
    final Query query = entityManager.createQuery(
            "from " + getDomain().getSimpleName() + " t  where t.thing = " + ((thing == null) ? " null" : " :thing"));
    if (thing != null) 
        query.setParameter("thing", thing);
    
    return query.getResultList();

顺便说一句,我对此很陌生,所以如果出于任何原因这不是一个好主意,请告诉我。谢谢。

【讨论】:

您不应该使用is 运算符:即... + " t where t.thing " + ((thing == null) ? "is null" : "= :thing") 能否详细说明这两者的区别? 使用= null会引发异常。尽管它可能取决于您运行哪个 dbms。在 SQL 中你有同样的问题,你也必须使用is null 而不是= nullnull 的问题是,一些数据库认为它并不是真正的空值,而是一个未确定的值,这意味着 null 不等于 null。因此null = null 永远不会是真的。见:***.com/questions/5066492/…

以上是关于如何得到hibernate显示在控制台的hql或sql语句?的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate:如何使用HQL设置NULL查询参数值?

hibernate hsql得到错误节点没有数据类型:org.hibernate.hql.ast.tree.IdentNode

(hibernate)如果我想查询表的总记录数,HQL语句应该怎么写?又如何获得值呢?

为啥得到 org.hibernate.hql.internal.ast.QuerySyntaxException: Path expected for join!加入 3 个表时

hibernate用HQL查询集合属性

Hibernate学习笔记 — HQL查询