Hibernate调试——定位查询源头

本文是我在importNew翻译的文章,首发在importNew,这里会定期更新链接

为什么有时Hibernate会在程序某一部分生成一条指定sql查询?这个问题让人非常难立马理解。当处理不是我们本人编写的代码时更是如此。

本文将展示怎样配置来产生Hibernate查询操作的日志。通过这些日志和一些小技巧来找出这些指定的查询为什么及在何处被运行。

Hibernate查询日志格式

Hibernate内建的查询日志格式例如以下:

select /* load your.package.Employee */ this_.code, ... 
from employee this_ 
where this_.employee_id=?

TRACE 12-04-2014@16:06:02  BasicBinder - binding parameter [1] as [NUMBER] - 1000

为什么Hibernate不能记载终于的查询日志?

须要注意的是。Hibernate仅仅记录从它发送到JDBC的准备语句(prepared statement)及參数。准备语句使用“?”作为查询參数的占位符,这些參数的实际值被记录在准备语句的下方。

这些准备语句和终于发送到数据库的sql语句是不同的,对于这些终于的查询操作Hibernate无法记录。

出现这样的情况的原因是Hibernate仅仅知道它发送给JDBC的准备语句和參数,实际的查询是由JDBC构建并发送给数据库的。

为了产生实际查询的日志。像log4jdbc这样的工具是不可缺少的,这里不会讨论怎样使用log4jdbc。

怎样找到原始查询操作

上述的可记录查询包括一条标注,在大多数情况下它能够标识某条起始查询语句。

假设一条查询是由载入引起的,那么标注便是/*load your.entity.Name*/。

假设是一条命名查询。那么标注则包括查询的名称。

假设它是一个相应很多延迟载入的查询,标注则会包括相应类的名称和引发该操作的属性值等。

设置Hibernate的查询日志

为了获得查询日志,须要将例如以下标签增加会话工厂的配置文件里:

<bean id= "entityManagerFactory" >
  ...
  <property name="jpaProperties" >
  <props>
      <prop key="hibernate.show_sql" >true</ prop>
      <prop key="hibernate.format_sql" >true</ prop>
      <prop key="hibernate.use_sql_comments">true</prop>
  </props>
</property>

上面的演示样例展示了Spring实体管理工厂的配置。以下是对一些标签的解释:

  • show_sql:激活查询日志功能。
  • format_sql:优雅地输出Sql。
  • use_sql_comments:加入一条解释型标注。

为了记录查询语句的參数信息,log4j或者相相应的信息是须要的。

<logger name="org.hibernate.type">
    <level value="trace" />
</logger >

假设上述功能都不能执行

在大多数情况下。use_sql_comments创建的标注是足够用来标识查询的起始。但假设这还不够,我们能够标识和数据表名相关联的查询返回的实体,并在返回的实体构造函数中设置断点。

假设一个实体没有构造函数,我们能够创建一个构造函数并把断点设置在super()函数调用中。

@Entity
public class Employee {
    public Employee() {
        super(); // put the breakpoint here
    }
    ...
}

设置断点后,跳转到包括程序堆栈信息的Debug界面并从头到尾运行一遍。这样在调用栈中将会出现查询操作在何处被创建。


原文地址:https://www.cnblogs.com/gccbuaa/p/6800119.html