1. 程式人生 > >Java-ORM-MyBatis:MyBatis 3 | SQL 語句構建器類

Java-ORM-MyBatis:MyBatis 3 | SQL 語句構建器類

ylbtech-Java-ORM-MyBatis:MyBatis 3 | SQL 語句構建器類

 

1.返回頂部
1、

SQL語句構建器類

問題

Java程式設計師面對的最痛苦的事情之一就是在Java程式碼中嵌入SQL語句。這麼來做通常是由於SQL語句需要動態來生成-否則可以將它們放到外部檔案或者儲存過程中。正如你已經看到的那樣,MyBatis在它的XML對映特性中有一個強大的動態SQL生成方案。但有時在Java程式碼內部建立SQL語句也是必要的。此時,MyBatis有另外一個特性可以幫到你,在減少典型的加號,引號,新行,格式化問題和嵌入條件來處理多餘的逗號或 AND 連線詞之前

。事實上,在Java程式碼中來動態生成SQL程式碼就是一場噩夢。例如:

String sql = "SELECT P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME, " "P.LAST_NAME,P.CREATED_ON, P.UPDATED_ON " + "FROM PERSON P, ACCOUNT A " + "INNER JOIN DEPARTMENT D on D.ID = P.DEPARTMENT_ID " + "INNER JOIN COMPANY C on D.COMPANY_ID = C.ID " + "WHERE (P.ID = A.ID AND P.FIRST_NAME like ?) " + "OR (P.LAST_NAME like ?) " + "GROUP BY P.ID " + "HAVING (P.LAST_NAME like ?) " + "OR (P.FIRST_NAME like ?) " + "ORDER BY P.ID, P.FULL_NAME";

The Solution

MyBatis 3提供了方便的工具類來幫助解決該問題。使用SQL類,簡單地建立一個例項來呼叫方法生成SQL語句。上面示例中的問題就像重寫SQL類那樣:

private String selectPersonSql() { return new SQL() {{ SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME"); SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON"); FROM("PERSON P"); FROM("ACCOUNT A"); INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID"); INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID"); WHERE("P.ID = A.ID"); WHERE("P.FIRST_NAME like ?"); OR(); WHERE("P.LAST_NAME like ?"); GROUP_BY("P.ID"); HAVING("P.LAST_NAME like ?"); OR(); HAVING("P.FIRST_NAME like ?"); ORDER_BY("P.ID"); ORDER_BY("P.FULL_NAME"); }}.toString(); }

該例中有什麼特殊之處?當你仔細看時,那不用擔心偶然間重複出現的"AND"關鍵字,或者在"WHERE"和"AND"之間的選擇,抑或什麼都不選。該SQL類非常注意"WHERE"應該出現在何處,哪裡又應該使用"AND",還有所有的字串連結。

SQL類

這裡給出一些示例:

// Anonymous inner class
public String deletePersonSql() { return new SQL() {{ DELETE_FROM("PERSON"); WHERE("ID = #{id}"); }}.toString(); } // Builder / Fluent style public String insertPersonSql() { String sql = new SQL() .INSERT_INTO("PERSON") .VALUES("ID, FIRST_NAME", "#{id}, #{firstName}") .VALUES("LAST_NAME", "#{lastName}") .toString(); return sql; } // With conditionals (note the final parameters, required for the anonymous inner class to access them) public String selectPersonLike(final String id, final String firstName, final String lastName) { return new SQL() {{ SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME"); FROM("PERSON P"); if (id != null) { WHERE("P.ID like #{id}"); } if (firstName != null) { WHERE("P.FIRST_NAME like #{firstName}"); } if (lastName != null) { WHERE("P.LAST_NAME like #{lastName}"); } ORDER_BY("P.LAST_NAME"); }}.toString(); } public String deletePersonSql() { return new SQL() {{ DELETE_FROM("PERSON"); WHERE("ID = #{id}"); }}.toString(); } public String insertPersonSql() { return new SQL() {{ INSERT_INTO("PERSON"); VALUES("ID, FIRST_NAME", "#{id}, #{firstName}"); VALUES("LAST_NAME", "#{lastName}"); }}.toString(); } public String updatePersonSql() { return new SQL() {{ UPDATE("PERSON"); SET("FIRST_NAME = #{firstName}"); WHERE("ID = #{id}"); }}.toString(); }
方法 描述
  • SELECT(String)
  • SELECT(String...)
開始或插入到 SELECT子句。 可以被多次呼叫,引數也會新增到 SELECT子句。 引數通常使用逗號分隔的列名和別名列表,但也可以是資料庫驅動程式接受的任意型別。
  • SELECT_DISTINCT(String)
  • SELECT_DISTINCT(String...)
開始或插入到 SELECT子句, 也可以插入 DISTINCT關鍵字到生成的查詢語句中。 可以被多次呼叫,引數也會新增到 SELECT子句。 引數通常使用逗號分隔的列名和別名列表,但也可以是資料庫驅動程式接受的任意型別。
  • FROM(String)
  • FROM(String...)
開始或插入到 FROM子句。 可以被多次呼叫,引數也會新增到 FROM子句。 引數通常是表名或別名,也可以是資料庫驅動程式接受的任意型別。
  • JOIN(String)
  • JOIN(String...)
  • INNER_JOIN(String)
  • INNER_JOIN(String...)
  • LEFT_OUTER_JOIN(String)
  • LEFT_OUTER_JOIN(String...)
  • RIGHT_OUTER_JOIN(String)
  • RIGHT_OUTER_JOIN(String...)
基於呼叫的方法,新增新的合適型別的 JOIN子句。 引數可以包含由列命和join on條件組合成標準的join。
  • WHERE(String)
  • WHERE(String...)
插入新的 WHERE子句條件, 由AND連結。可以多次被呼叫,每次都由AND來連結新條件。使用 OR() 來分隔OR
OR() 使用OR來分隔當前的 WHERE子句條件。 可以被多次呼叫,但在一行中多次呼叫或生成不穩定的SQL
AND() 使用AND來分隔當前的 WHERE子句條件。 可以被多次呼叫,但在一行中多次呼叫或生成不穩定的SQL。因為 WHERE 和 HAVING 二者都會自動連結 AND, 這是非常罕見的方法,只是為了完整性才被使用。
  • GROUP_BY(String)
  • GROUP_BY(String...)
插入新的 GROUP BY子句元素,由逗號連線。 可以被多次呼叫,每次都由逗號連線新的條件。
  • HAVING(String)
  • HAVING(String...)
插入新的 HAVING子句條件。 由AND連線。可以被多次呼叫,每次都由AND來連線新的條件。使用 OR() 來分隔OR.
  • ORDER_BY(String)
  • ORDER_BY(String...)
插入新的 ORDER BY子句元素, 由逗號連線。可以多次被呼叫,每次由逗號連線新的條件。
DELETE_FROM(String) 開始一個delete語句並指定需要從哪個表刪除的表名。通常它後面都會跟著WHERE語句!
INSERT_INTO(String) 開始一個insert語句並指定需要插入資料的表名。後面都會跟著一個或者多個VALUES() or INTO_COLUMNS() and INTO_VALUES()。
  • SET(String)
  • SET(String...)
針對update語句,插入到"set"列表中
UPDATE(String) 開始一個update語句並指定需要更新的表明。後面都會跟著一個或者多個SET(),通常也會有一個WHERE()。
VALUES(String, String) 插入到insert語句中。第一個引數是要插入的列名,第二個引數則是該列的值。
INTO_COLUMNS(String...) Appends columns phrase to an insert statement. This should be call INTO_VALUES() with together.
INTO_VALUES(String...) Appends values phrase to an insert statement. This should be call INTO_COLUMNS() with together.

Since version 3.4.2, you can use variable-length arguments as follows:

public String selectPersonSql() { return new SQL() .SELECT("P.ID", "A.USERNAME", "A.PASSWORD", "P.FULL_NAME", "D.DEPARTMENT_NAME", "C.COMPANY_NAME") .FROM("PERSON P", "ACCOUNT A") .INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID", "COMPANY C on D.COMPANY_ID = C.ID") .WHERE("P.ID = A.ID", "P.FULL_NAME like #{name}") .ORDER_BY("P.ID", "P.FULL_NAME") .toString(); } public String insertPersonSql() { return new SQL() .INSERT_INTO("PERSON") .INTO_COLUMNS("ID", "FULL_NAME") .INTO_VALUES("#{id}", "#{fullName}") .toString(); } public String updatePersonSql() { return new SQL() .UPDATE("PERSON") .SET("FULL_NAME = #{fullName}", "DATE_OF_BIRTH = #{dateOfBirth}") .WHERE("ID = #{id}") .toString(); }

SqlBuilder 和 SelectBuilder (已經廢棄)

在3.2版本之前,我們使用了一點不同的做法,通過實現ThreadLocal變數來掩蓋一些導致Java DSL麻煩的語言限制。但這種方式已經廢棄了,現代的框架都歡迎人們使用構建器型別和匿名內部類的想法。因此,SelectBuilder 和 SqlBuilder 類都被廢棄了。

下面的方法僅僅適用於廢棄的SqlBuilder 和 SelectBuilder 類。

方法 描述
BEGIN() /RESET() 這些方法清空SelectBuilder類的ThreadLocal狀態,並且準備一個新的構建語句。開始新的語句時, BEGIN()讀取得最好。 由於一些原因(在某些條件下,也許是邏輯需要一個完全不同的語句),在執行中清理語句 RESET()讀取得最好。
SQL() 返回生成的 SQL() 並重置 SelectBuilder 狀態 (好像 BEGIN() 或 RESET() 被呼叫了). 因此,該方法只能被呼叫一次!

SelectBuilder 和 SqlBuilder 類並不神奇,但是知道它們如何工作也是很重要的。 SelectBuilder 使用 SqlBuilder 使用了靜態匯入和ThreadLocal變數的組合來開啟整潔語法,可以很容易地和條件交錯。使用它們,靜態匯入類的方法即可,就像這樣(一個或其它,並非兩者):

import static org.apache.ibatis.jdbc.SelectBuilder.*;
import static org.apache.ibatis.jdbc.SqlBuilder.*;

這就允許像下面這樣來建立方法:

/* DEPRECATED */
public String selectBlogsSql() { BEGIN(); // Clears ThreadLocal variable SELECT("*"); FROM("BLOG"); return SQL(); }
/* DEPRECATED */
private String selectPersonSql() { BEGIN(); // Clears ThreadLocal variable SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME"); SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON"); FROM("PERSON P"); FROM("ACCOUNT A"); INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID"); INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID"); WHERE("P.ID = A.ID"); WHERE("P.FIRST_NAME like ?"); OR(); WHERE("P.LAST_NAME like ?"); GROUP_BY("P.ID"); HAVING("P.LAST_NAME like ?"); OR(); HAVING("P.FIRST_NAME like ?"); ORDER_BY("P.ID"); ORDER_BY("P.FULL_NAME"); return SQL(); }
2、
2.返回頂部
 
3.返回頂部
 
4.返回頂部
 
5.返回頂部
1、 http://www.mybatis.org/mybatis-3/zh/statement-builders.html 2、  
6.返回頂部
 
warn 作者:ylbtech
出處:http://ylbtech.cnblogs.com/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。