引言:为什么这样的需求,源自公司项目需要,公司的项目使用java的struts2+spring2.5+oracle中间件tuxedo,数据库用的是Oracle,但由于不直接连接数据库,用中间件处理的方式,又不希望有太多服务,所以就开始网络找资料整理编码了。大概花了一个多星期完成了这个任务,现在整理出来与大家分享,也是自己知识的梳理。
1.需要导入相关的jar包: [按字母顺序排列]
antlr-2.7.5H3.jar 语言转换工,Hibernate利用它实现 HQL 到 SQL的转换
asm.jar ASM 字节转换库
cglib-2.1.2.jar 高效的代码生成工具, Hibernate用它在运行时扩展 Java类和实现 Java 接口
classes12.jar Oracle数据库驱动
commons-collections-2.1.1.jar Apache 的工具集,用来增强Java对集合的处理能力
commons-logging-1.0.4.jar Apache 软件基金组所提供的日志工具
dom4j-1.6.1.jar dom4j XML 解析器
hibernate.jar Hibernate的核心库
jta.jar 标准的 JAVA 事务处理接口
2. 在项目src 下加入 hibernate.cfg.xml ,并配置
配置数据库方言dialect,和实体映射文件mapping,其他属性可以不用配置,因为不需要用到,注意:数据库连接url 不要加,因为加了后,程序会试图去连接。
1 <?xml version='1.0' encoding='UTF-8'?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5 6 <!-- Generated by MyEclipse Hibernate Tools. --> 7 <hibernate-configuration> 8 <session-factory> 9 <!-- 因为项目只需用Hibernate把hql转换成sql,包括无参数,有参数及需要格式化的参数 10 <property name="connection.url"> 11 jdbc:oracle:thin:@127.0.0.1:1521:javacrm 12 </property> 13 <property name="connection.username">scott</property> 14 <property name="connection.password">tiger</property> 15 <property name="connection.driver_class"> 16 oracle.jdbc.driver.OracleDriver 17 </property> 18 <property name="show_sql">true</property> 19 <property name="format_sql">true</property> 20 --> 21 <!-- 数据库方言 --> 22 <property name="dialect"> 23 org.hibernate.dialect.Oracle10gDialect 24 </property> 25 <!-- 实体映射文件 --> 26 <mapping resource="com/test/bean/Student.hbm.xml"/> 27 <mapping resource="com/test/bean/BasDicConstant.hbm.xml"/> 28 29 </session-factory> 30 </hibernate-configuration>
3. 编写获取Session公共类 DbUtil.java
1 package com.test.util; 2 3 import org.hibernate.HibernateException; 4 import org.hibernate.Session; 5 import org.hibernate.SessionFactory; 6 import org.hibernate.cfg.Configuration; 7 8 public class DbUtil { 9 10 private static final SessionFactory sessionFactory; 11 public static final ThreadLocal session = new ThreadLocal(); 12 13 static { 14 try { 15 sessionFactory = new Configuration().configure() 16 .buildSessionFactory(); 17 } catch (Throwable ex) { 18 ex.printStackTrace(); 19 throw new ExceptionInInitializerError(ex); 20 } 21 } 22 23 public static Session currentSession() throws HibernateException { 24 Session s = (Session) session.get(); 25 if (s == null || !s.isOpen()) { 26 s = sessionFactory.openSession(); 27 session.set(s); 28 } 29 return s; 30 } 31 32 public static void closeSession() throws HibernateException { 33 Session s = (Session) session.get(); 34 session.set(null); 35 if (s != null) 36 s.close(); 37 } 38 39 public SessionFactory getSessionFactory() { 40 return sessionFactory; 41 } 42 43 }
4. 编写核心转换类 HqlToSql.java
1 package com.test.hqlc; 2 3 import java.util.Collections; 4 import java.util.List; 5 6 import org.hibernate.Session; 7 import org.hibernate.hql.ast.QueryTranslatorImpl; 8 import org.hibernate.impl.SessionFactoryImpl; 9 10 import com.test.util.DbUtil; 11 12 /** 13 * 传入hql语句,参数值列表,返回可执行的sql语句 14 * @author xiufen.huang by 2014-07-03 15 */ 16 public class HqlToSql { 17 18 /** 19 * 处理结果信息,成功:为空,失败:错误信息 20 */ 21 private static String resultMsg = "" ; 22 private static final String nullMsg = "传入的hql为null或空!"; 23 24 /** 25 * 获取处理结果信息,成功:为空,失败:错误信息 26 * @return 处理结果信息 27 */ 28 public static String getResultMsg() { 29 return resultMsg; 30 } 31 32 /** 33 * 将hql语句转换为sql语句,无参数 34 * @param hql 要转换的hql语句 35 * @return 可执行的sql语句,当返回null,可以通过getResultMsg()方法查看处理结果信息 36 */ 37 public static String transHqlToSql(String hql){ 38 // 当hql为null或空时,直接返回null 39 if (hql == null || hql.equals("")) { 40 resultMsg = nullMsg; 41 return null; 42 } 43 // 获取当前session 44 Session session = DbUtil.currentSession(); 45 // 得到session工厂实现类 46 SessionFactoryImpl sfi = (SessionFactoryImpl)session.getSessionFactory(); 47 // 得到Query转换器实现类 48 QueryTranslatorImpl queryTranslator = new QueryTranslatorImpl(hql, hql, Collections.EMPTY_MAP, sfi); 49 queryTranslator.compile(Collections.EMPTY_MAP, false); 50 // 得到sql 51 String sql = queryTranslator.getSQLString(); 52 // 关闭session 53 DbUtil.closeSession(); 54 return sql; 55 } 56 57 /** 58 * 将hql语句转换为sql语句,不需要格式化参数的情况 59 * @param hql 要转换的hql语句 60 * @param paramValues hql参数值列表,注意与参数的顺序一致 61 * @return 可执行的sql语句,当返回null,可以通过getResultMsg()方法查看处理结果信息 62 */ 63 public static String transHqlToSql(String hql,List paramValues){ 64 // 要返回的sql语句 65 String sql = transHqlToSql(hql); 66 // 当为null或空时,返回null 67 if (sql == null || sql.equals("")) { 68 resultMsg = nullMsg; 69 return null; 70 } 71 72 // 赋参数值 73 if (paramValues != null && paramValues.size() > 0) { 74 for (int i = 0; i < paramValues.size(); i++) { 75 sql = sql.replaceFirst("\\?", "\\'"+paramValues.get(i).toString()+"\\'"); 76 } 77 } 78 return sql; 79 } 80 81 /** 82 * 将hql语句转换为sql语句,有日期,Char等需要格式化参数的情况 83 * @param hql 要转换的hql语句 84 * @param paramValues hql参数值列表,注意与参数的顺序一致 85 * @return 可执行的sql语句,当返回null,可以通过getResultMsg()方法查看处理结果信息 86 */ 87 public static String formatHqlToSql(String hql,List<TransTemp> paramValues){ 88 // 要返回的sql语句 89 String sql = transHqlToSql(hql); 90 // 当为null或空时,返回null 91 if (sql == null || sql.equals("")) { 92 resultMsg = nullMsg; 93 return null; 94 } 95 96 // 赋参数值 97 if (paramValues != null && paramValues.size() > 0) { 98 for (int i = 0; i < paramValues.size(); i++) { 99 TransTemp tt = paramValues.get(i); 100 sql = sql.replaceFirst("\\?", tt.getOracleFormatString()); 101 } 102 } 103 return sql; 104 } 105 106 }
5.测试实例 HqlToSqlTest.java
1 package com.test.hqlc; 2 3 import java.text.SimpleDateFormat; 4 import java.util.ArrayList; 5 import java.util.Date; 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 import java.sql.Types; 10 11 import org.hibernate.Query; 12 import org.hibernate.Session; 13 14 import com.test.bean.Student; 15 import com.test.bean.BasDicConstant; 16 import com.test.util.DbUtil; 17 18 public class HqlToSqlTest { 19 20 public static void main(String[] args) { 21 22 // String hql = "from Student"; 23 String hql = "from Student where studentName like :stuName and birthDay between :dat1 and :dat2"; 24 25 26 List vals = new ArrayList(); 27 vals.add("%L%"); 28 vals.add("1990-02-28 00:00:00"); 29 vals.add("1992-02-28 23:59:59"); 30 31 String sql1 = HqlToSql.transHqlToSql(hql); 32 System.out.println("hql转换成sql无参数:"+sql1); 33 34 String sql2 = HqlToSql.transHqlToSql(hql, vals); 35 36 System.out.println("hql转换成sql有参数:"+sql2); 37 System.out.println("转换结果信息: "+HqlToSql.getResultMsg()); 38 39 // 有格式化字符串 40 List<TransTemp> list = new ArrayList<TransTemp>(); 41 42 // 构造参数 43 TransTemp tt1 = new TransTemp(); 44 tt1.setParamSqlType(Types.VARCHAR); 45 tt1.setParamValue("%L%"); 46 list.add(tt1); 47 48 TransTemp tt2 = new TransTemp(Types.TIME,"1990-02-28 00:00:00"); 49 list.add(tt2); 50 51 TransTemp tt3 = new TransTemp(Types.DATE,new Date(),"yyyy-mm-dd hh24:mi:ss"); 52 list.add(tt3); 53 54 String tSql = HqlToSql.formatHqlToSql(hql, list); 55 System.out.println("hql转换成格式化参数的sql: "+tSql); 56 57 } 58 }
6.测试结果:
1 hql转换成sql无参数:select student0_.student_id as student1_0_, student0_.student_name as student2_0_, student0_.student_age as student3_0_, student0_.status as status0_, student0_.birth_Day as birth5_0_ from students student0_ where (student0_.student_name like ?) and (student0_.birth_Day between ? and ?) 2 hql转换成sql有参数:select student0_.student_id as student1_0_, student0_.student_name as student2_0_, student0_.student_age as student3_0_, student0_.status as status0_, student0_.birth_Day as birth5_0_ from students student0_ where (student0_.student_name like '%L%') and (student0_.birth_Day between '1990-02-28 00:00:00' and '1992-02-28 23:59:59') 3 转换结果信息: 4 hql转换成格式化参数的sql: select student0_.student_id as student1_0_, student0_.student_name as student2_0_, student0_.student_age as student3_0_, student0_.status as status0_, student0_.birth_Day as birth5_0_ from students student0_ where (student0_.student_name like '%L%') and (student0_.birth_Day between to_date('1990-02-28 00:00:00','yyyy-mm-dd hh24:mi:ss') and to_date('2014-07-24 17:21:38','yyyy-mm-dd hh24:mi:ss'))
7. 参考资料:
http://coffeelover.iteye.com/blog/462139
http://blog.csdn.net/w_l_j/article/details/7064416
http://www.cnblogs.com/yql1986/archive/2011/09/30/2196621.html?ADUIN=416455569&ADSESSION=1404434624&ADTAG=CLIENT.QQ.5329_.0&ADPUBNO=26349
8.源码 Hibernate02.rar