引言:為什么這樣的需求,源自公司項目需要,公司的項目使用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