本章主要研究在Hibernate中,如何在生成的SQL当中将参数占位符?替换成实际的值,但同时还支持XA分布式事务管理系统。
1. Hibernate生成的SQL
在Hibernate配置中,可以配置让Hibernate自动输出其生成的SQL语句,以便开发人员了解程序底层的机制,方便开发人员调试程序。要让Hibernate输出SQL语句,只要在persistence.xml文件中配置:
1 | …… |
然而,在生成SQL语句的时候,Hibernate并不会将参数占位符?替换成具体的参数:
1 | Hibernate: |
虽然可以让Hibernate在SQL语句之后输出参数,但是在参数较多且比较复杂的时候,这种方式还是使得调试非常不便。
2. 使用P6spy辅助Hibernate生成SQL
本章中,我们借助p6spy库的功能来让Hibernate生成的SQL语句中附带具体的参数。
P6spy的功能非常简单,它其实是一个JDBC驱动代理。其主要功能就是让SQL语句通过p6spy的时候输出同时将要执行的SQL语句转交给真正的JDBC驱动真正执行。因此,需要在原来需要JDBC驱动的地方替换成p6spay驱动,然后再p6spay中配置真正的JDBC驱动到底是谁。
对于简单的JDBC应用来说,配置非常简单。然而,我们的程序中使用了XA分布式事务管理框架,配置相对复杂。好在新版本的P6spay本身也是支持XA事务管理框架的。
首先,我们需要在build.gradle中添加p6spy依赖:
1 | /* |
然后,再在src/main/resource/目录中添加spy-datasource.properties文件(原来的datasource.properties依然要保留),来配置p6spy的数据源:
1 | #配置spy的数据源 |
其配置几乎和原来的datasource.properties一致,区别在于数据源的名称使用p6spy提供的数据源驱动,驱动属性当中的realDataSource属性配置成原来的数据源名称myDS,以实现执行SQL语句的委托。需要提供一个和源数据源JNDI名称不同的全新名称来查找p6spy数据源,本程序中使用名称spayDS。
修改persistence.xml文件,现在需要使用spyDS为JNDI名称来查找数据源:
1 | <persistence version="2.1" |
然后,修改TransactionManagerSetup类,现在需要加载两次数据源,第一次加载真正的数据源,并初始化。然后再加载p6spy数据源,并依赖于真正数据源:
1 | package com.rainsia.hibernate.env; |
然后,在src/main/resources目录中创建一个spy.properties用于配置p6spy的输出:
1 | # 使用slf4j作为日期记录器 |
然后运行程序,可以看到如下输出:
从中可以看出,现在除了输出Hibernate生成的SQL语句之外,p6spy还输出的替换占位符之后的输出。使用MultiLineFormat的时候,p6spy的每条日志会分为两行,第一行记录了原来Hibernate的输出,第二行记录了替换参数之后的输出:
1 | …… |
然而,第一行的内容和Hibernate输出的结果几乎是重复的。因此,我们可以配置CustomLineFormat来输出,这时候只输出一行内容:
1 | …… |
最终,我们在Hibernate中配置了p6spy库,让其替换SQL语句中的占位符,方便开发人员调试程序。同时又不改变原来的数据库驱动和对XA数据源的支持。