日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
創(chuàng)新互聯(lián)MyBatis教程:MyBatis3SQL語句構建器

問題

Java 程序員面對的最痛苦的事情之一就是在 Java 代碼中嵌入 SQL 語句。這通常是因為需要動態(tài)生成 SQL 語句,不然我們可以將它們放到外部文件或者存儲過程中。如你所見,Mybatis 在 XML 映射中具備強大的 SQL 動態(tài)生成能力。但有時,我們還是需要在 Java 代碼里構建 SQL 語句。此時,MyBatis 有另外一個特性可以幫到你,讓你從處理典型問題中解放出來,比如加號、引號、換行、格式化問題、嵌入條件的逗號管理及 AND 連接。確實,在 Java 代碼中動態(tài)生成 SQL 代碼真的就是一場噩夢。例如:

創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設、高性價比東坡網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式東坡網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設找我們,業(yè)務覆蓋東坡地區(qū)。費用合理售后完善,10多年實體公司更值得信賴。

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";

    

解決方案

MyBatis 3 提供了方便的工具類來幫助解決此問題。借助 SQL 類,我們只需要簡單地創(chuàng)建一個實例,并調用它的方法即可生成 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();
}

這個例子有什么特別之處嗎?仔細看一下你會發(fā)現(xiàn),你不用擔心可能會重復出現(xiàn)的 "AND" 關鍵字,或者要做出用 "WHERE" 拼接還是 "AND" 拼接還是不用拼接的選擇。SQL 類已經(jīng)為你處理了哪里應該插入 "WHERE"、哪里應該使用 "AND" 的問題,并幫你完成所有的字符串拼接工作。

SQL 類

這里有一些示例:

// 匿名內部類風格
public String deletePersonSql() {
  return new SQL() {{
    DELETE_FROM("PERSON");
    WHERE("ID = #{id}");
  }}.toString();
}

// Builder / Fluent 風格
public String insertPersonSql() {
  String sql = new SQL()
    .INSERT_INTO("PERSON")
    .VALUES("ID, FIRST_NAME", "#{id}, #{firstName}")
    .VALUES("LAST_NAME", "#{lastName}")
    .toString();
  return sql;
}

// 動態(tài)條件(注意參數(shù)需要使用 final 修飾,以便匿名內部類對它們進行訪問)
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子句。可以被多次調用,參數(shù)會被追加到 SELECT 子句。 參數(shù)通常使用逗號分隔的列名和別名列表,但也可以是數(shù)據(jù)庫驅動程序接受的任意參數(shù)。
  • SELECT_DISTINCT(String)
  • SELECT_DISTINCT(String...)
開始新的或追加到已有的 SELECT子句,并添加 DISTINCT 關鍵字到生成的查詢中??梢员欢啻握{用,參數(shù)會被追加到 SELECT 子句。 參數(shù)通常使用逗號分隔的列名和別名列表,但也可以是數(shù)據(jù)庫驅動程序接受的任意參數(shù)。
  • FROM(String)
  • FROM(String...)
開始新的或追加到已有的 FROM子句??梢员欢啻握{用,參數(shù)會被追加到 FROM子句。 參數(shù)通常是一個表名或別名,也可以是數(shù)據(jù)庫驅動程序接受的任意參數(shù)。
  • 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 子句。 參數(shù)可以包含一個由列和連接條件構成的標準連接。
  • 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 子句,使用逗號拼接??梢远啻伪徽{用,每次調用會使用逗號拼接新的條件。
  • LIMIT(String)
  • LIMIT(int)
追加新的 LIMIT 子句。 僅在 SELECT()、UPDATE()、DELETE() 時有效。 當在 SELECT() 中使用時,應該配合 OFFSET() 使用。(于 3.5.2 引入)
  • OFFSET(String)
  • OFFSET(long)
追加新的 OFFSET 子句。 僅在 SELECT() 時有效。 當在 SELECT() 時使用時,應該配合 LIMIT() 使用。(于 3.5.2 引入)
  • OFFSET_ROWS(String)
  • OFFSET_ROWS(long)
追加新的 OFFSET n ROWS 子句。 僅在 SELECT() 時有效。 該方法應該配合 FETCH_FIRST_ROWS_ONLY() 使用。(于 3.5.2 加入)
  • FETCH_FIRST_ROWS_ONLY(String)
  • FETCH_FIRST_ROWS_ONLY(int)
追加新的 FETCH FIRST n ROWS ONLY 子句。 僅在 SELECT() 時有效。 該方法應該配合 OFFSET_ROWS() 使用。(于 3.5.2 加入)
DELETE_FROM(String) 開始新的 delete 語句,并指定刪除表的表名。通常它后面都會跟著一個 WHERE 子句!
INSERT_INTO(String) 開始新的 insert 語句,并指定插入數(shù)據(jù)表的表名。后面應該會跟著一個或多個 VALUES() 調用,或 INTO_COLUMNS() 和 INTO_VALUES() 調用。
  • SET(String)
  • SET(String...)
對 update 語句追加 "set" 屬性的列表
UPDATE(String) 開始新的 update 語句,并指定更新表的表名。后面都會跟著一個或多個 SET() 調用,通常也會有一個 WHERE() 調用。
VALUES(String, String) 追加數(shù)據(jù)值到 insert 語句中。第一個參數(shù)是數(shù)據(jù)插入的列名,第二個參數(shù)則是數(shù)據(jù)值。
INTO_COLUMNS(String...) 追加插入列子句到 insert 語句中。應與 INTO_VALUES() 一同使用。
INTO_VALUES(String...) 追加插入值子句到 insert 語句中。應與 INTO_COLUMNS() 一同使用。
ADD_ROW() 添加新的一行數(shù)據(jù),以便執(zhí)行批量插入。(于 3.5.2 引入)

注意,SQL 類將原樣插入 ?LIMIT?、?OFFSET?、?OFFSET n ROWS? 以及 ?FETCH FIRST n ROWS ONLY? 子句。換句話說,類庫不會為不支持這些子句的數(shù)據(jù)庫執(zhí)行任何轉換。 因此,用戶應該要了解目標數(shù)據(jù)庫是否支持這些子句。如果目標數(shù)據(jù)庫不支持這些子句,產生的 SQL 可能會引起運行錯誤。

從版本 3.4.2 開始,你可以像下面這樣使用可變長度參數(shù):

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();
}

從版本 3.5.2 開始,你可以像下面這樣構建批量插入語句:

public String insertPersonsSql() {
  // INSERT INTO PERSON (ID, FULL_NAME)
  //     VALUES (#{mainPerson.id}, #{mainPerson.fullName}) , (#{subPerson.id}, #{subPerson.fullName})
  return new SQL()
    .INSERT_INTO("PERSON")
    .INTO_COLUMNS("ID", "FULL_NAME")
    .INTO_VALUES("#{mainPerson.id}", "#{mainPerson.fullName}")
    .ADD_ROW()
    .INTO_VALUES("#{subPerson.id}", "#{subPerson.fullName}")
    .toString();
}

從版本 3.5.2 開始,你可以像下面這樣構建限制返回結果數(shù)的 SELECT 語句,:

public String selectPersonsWithOffsetLimitSql() {
  // SELECT id, name FROM PERSON
  //     LIMIT #{limit} OFFSET #{offset}
  return new SQL()
    .SELECT("id", "name")
    .FROM("PERSON")
    .LIMIT("#{limit}")
    .OFFSET("#{offset}")
    .toString();
}

public String selectPersonsWithFetchFirstSql() {
  // SELECT id, name FROM PERSON
  //     OFFSET #{offset} ROWS FETCH FIRST #{limit} ROWS ONLY
  return new SQL()
    .SELECT("id", "name")
    .FROM("PERSON")
    .OFFSET_ROWS("#{offset}")
    .FETCH_FIRST_ROWS_ONLY("#{limit}")
    .toString();
}

SqlBuilder 和 SelectBuilder (已經(jīng)廢棄)

在版本 3.2 之前,我們的實現(xiàn)方式不太一樣,我們利用 ?ThreadLocal ?變量來掩蓋一些對 Java DSL 不太友好的語言限制?,F(xiàn)在,現(xiàn)代 SQL 構建框架使用的構建器和匿名內部類思想已被人們所熟知。因此,我們廢棄了基于這種實現(xiàn)方式的 ?SelectBuilder ?和 ?SqlBuilder ?類。

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

方法 描述
BEGIN() / RESET() 這些方法清空 SelectBuilder 類的 ThreadLocal 狀態(tài),并準備好構建一個新的語句。開始新的語句時,BEGIN() 是最名副其實的(可讀性最好的)。但如果由于一些原因(比如程序邏輯在某些條件下需要一個完全不同的語句),在執(zhí)行過程中要重置語句構建狀態(tài),就很適合使用 RESET()。
SQL() 該方法返回生成的 SQL() 并重置 SelectBuilder 狀態(tài)(等價于調用了 BEGIN() 或 RESET())。因此,該方法只能被調用一次!

?SelectBuilder ?和 ?SqlBuilder ?類并不神奇,但最好還是知道它們的工作原理。 ?SelectBuilder ?以及 ?SqlBuilder ?借助靜態(tài)導入和 ?ThreadLocal ?變量實現(xiàn)了對插入條件友好的簡潔語法。要使用它們,只需要靜態(tài)導入這個類的方法即可,就像這樣(只能使用其中的一條,不能同時使用):

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

然后就可以像下面這樣創(chuàng)建一些方法:

/* 已被廢棄 */
public String selectBlogsSql() {
  BEGIN(); // 重置 ThreadLocal 狀態(tài)變量
  SELECT("*");
  FROM("BLOG");
  return SQL();
}
/* 已被廢棄 */
private String selectPersonSql() {
  BEGIN(); // 重置 ThreadLocal 狀態(tài)變量
  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();
}


文章題目:創(chuàng)新互聯(lián)MyBatis教程:MyBatis3SQL語句構建器
瀏覽地址:http://www.5511xx.com/article/cogiepe.html