首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Hibernate 擁抱 MyBatis 風格:基於 FreeMarker 的 SQL/HQL 模板化方案

     編輯:Java 綜合教學

動機:結合 Hibernate ORM 與 MyBatis 靈活 SQL

Hibernate 標準 HQL/Criteria 雖物件化但複雜查詢受限;MyBatis XML 映射極致靈活卻失去 ORM 便利。本文介紹一種混合方案:以 FreeMarker 模板引擎解析 XML 定義的 SQL/HQL,緩存後由 Hibernate 執行,實現「註解/XML 雙模式、動態 SQL、集中管理」。

架構圖解

XML (User.query.xml) 
    → 掃描解析器 (掃描 *.query.xml)
    → FreeMarker 渲染 (參數綁定、條件片段)
    → QueryFactory 緩存 (Key: 實體類 + 查詢名)
    → DBAdapter (Hibernate 原生 Query 執行)
    → DAO 層調用

核心組件

1. 约束定義 Query.dtd

定義 XML 結構:<query name="...">、<sql>/<hql>、<param>、<if>/<where> 等 FreeMarker 指令。

2. 實體類 User.java

@Entity @Table(name="t_user")
public class User {
    @Id @GeneratedValue Long id;
    String username; String email; Integer status;
    // getter/setter
}

3. XML 查詢定義 User.query.xml

<queries entity="com.example.User">
  <query name="findByCondition">
    <hql>
      FROM User u
      <#if username??>WHERE u.username LIKE :username</#if>
      <#if status??>AND u.status = :status</#if>
      ORDER BY u.id DESC
    </hql>
  </query>
</queries>

4. 解析與緩存 QueryFactory

  • Spring 啟動時掃描 classpath:*.query.xml。
  • SAX/DOM 解析提取 <query> 節點,預編譯 FreeMarker 模板。
  • 以 EntityClass#queryName 為 Key 緩存 Template 物件。

5. 執行適配器 HibernateSingleDBAdapter

public class HibernateSingleDBAdapter implements DBAdapter {
    private SessionFactory sessionFactory;
    private QueryFactory queryFactory;

    public  List query(String queryName, Map params, Class entityClass) {
        Template tpl = queryFactory.getTemplate(entityClass, queryName);
        String renderedHql = FreeMarkerTemplateUtils.processTemplateIntoString(tpl, params);
        Query query = sessionFactory.getCurrentSession().createQuery(renderedHql);
        params.forEach(query::setParameter);
        return query.list();
    }
}

6. Spring 裝配

<bean id="queryFactory" class="com.example.db.QueryFactory">
    <property name="files" value="classpath:**/*.query.xml"/>
</bean>

<bean id="dbAdapter" class="com.example.db.HibernateSingleDBAdapter">
    <property name="sessionFactory" ref="sessionFactory"/>
    <property name="queryFactory" ref="queryFactory"/>
</bean>

7. DAO 使用

public class UserDao extends AbstractDao {
    public List findByCondition(String username, Integer status) {
        Map params = new HashMap<>();
        if (username != null) params.put("username", "%" + username + "%");
        if (status != null) params.put("status", status);
        return dbAdapter.query("findByCondition", params, User.class);
    }
}

優缺點權衡

優點缺點/風險
動態 SQL 能力接近 MyBatis引入 FreeMarker 依賴,啟動解析耗時
SQL/HQL 集中管理,易審計優化模板語法錯誤運行時才發現,需完善測試
保留 Hibernate 實體映射、緩存、攔截器非標準方案,團隊學習成本、維護風險較高
支援註解/XML 雙模式共存複雜關聯查詢模板易膨脹,建議配合 View/DTO

現代替代方案建議

  • Spring Data JPA Specifications / QueryDSL:類型安全動態查詢,無模板風險。
  • MyBatis-Plus / MyBatis-Flex:若極度依賴手寫 SQL,直接全盤 MyBatis 更成熟。
  • Hibernate @NamedQuery / @NamedNativeQuery:原生支援 XML/註解集中定義,零額外依賴。

此方案適合「既有 Hibernate 體系、需少量複雜動態 SQL、團隊熟悉 FreeMarker」的遷移過渡期。新專案建議直接選型成熟方案,避免重複造輪子。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved