Github Mybatis深入学习之SQL生成类 .

MyBatis是怎样生成SQL语句的,我们对此非常好奇。所以还是来了解了解吧,原文地址: http://mybatis.github.io/mybatis-3/statement-builders.html

1、问题(problem)

         一个Java开发人员永远不会有最讨厌的事情之一是在Java代码中嵌入SQL。通常这样做是因为SQL可以动态生成 - 否则,你可能在一个文件或一个存储过程。正如你已经看到的,MyBatis有一个有力的回答,动态SQL生成XML映射功能。然而,有时有必要建立一个SQL语句的字符串里面的Java代码。在这种情况下,MyBatis有更多的功能来帮助你摆脱烦恼,减少自己典型的乱七八糟的加号,引号,换行,格式化的问题和嵌套的条件来处理多余的逗号和连词。事实上,在Java中动态生成SQL代码是一个真正的噩梦。例如:

  1. <SPAN style="FONT-SIZE: 12px">String sql = "SELECT P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME, "  
  2. "P.LAST_NAME,P.CREATED_ON, P.UPDATED_ON " +  
  3. "FROM PERSON P, ACCOUNT A " +  
  4. "INNER JOIN DEPARTMENT D on D.ID = P.DEPARTMENT_ID " +  
  5. "INNER JOIN COMPANY C on D.COMPANY_ID = C.ID " +  
  6. "WHERE (P.ID = A.ID AND P.FIRST_NAME like ?) " +  
  7. "OR (P.LAST_NAME like ?) " +  
  8. "GROUP BY P.ID " +  
  9. "HAVING (P.LAST_NAME like ?) " +  
  10. "OR (P.FIRST_NAME like ?) " +  
  11. "ORDER BY P.ID, P.FULL_NAME";</SPAN>  
<span style="font-size:12px;">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";</span>

2、解决方案(solution)

         MyBatis的3提供了一个方便的实用程序工具类以解决此问题。随着SQL类,你只需创建一个实例,让你一次调用方法而不是一步就建立一个SQL语句。SQL类中重写时,上面的例子问题看起来像这样:

  1. <SPAN style="FONT-SIZE: 12px">private String selectPersonSql() {  
  2.   return new SQL() {{  
  3.     SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME");  
  4.     SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON");  
  5.     FROM("PERSON P");  
  6.     FROM("ACCOUNT A");  
  7.     INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID");  
  8.     INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID");  
  9.     WHERE("P.ID = A.ID");  
  10.     WHERE("P.FIRST_NAME like ?");  
  11.     OR();  
  12.     WHERE("P.LAST_NAME like ?");  
  13.     GROUP_BY("P.ID");  
  14.     HAVING("P.LAST_NAME like ?");  
  15.     OR();  
  16.     HAVING("P.FIRST_NAME like ?");  
  17.     ORDER_BY("P.ID");  
  18.     ORDER_BY("P.FULL_NAME");  
  19.   }}.toString();  
  20. }</SPAN>  
<span style="font-size:12px;">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();
}</span>
关于那个例子有什么特别之处呢?好吧,如果你仔细看,它并不担心意外复制“AND”关键字,或选择之间的“WHERE”和“AND”或根本没有。 SQL类需要关心理解的是其“WHERE”需要去“AND”应使用所有的字符串连接。

3、SQL类

       这里有一些例子:

  1. <SPAN style="FONT-SIZE: 12px">// Anonymous inner class   
  2. public String deletePersonSql() {  
  3.   return new SQL() {{  
  4.     DELETE_FROM("PERSON");  
  5.     WHERE("ID = ${id}");  
  6.   }}.toString();  
  7. }  
  8.   
  9. // Builder / Fluent style   
  10. public String insertPersonSql() {  
  11.   String sql = new SQL()  
  12.     .INSERT_INTO("PERSON");  
  13.     .VALUES("ID, FIRST_NAME""${id}, ${firstName}");  
  14.     .VALUES("LAST_NAME""${lastName}")  
  15.     .toString();  
  16.   return sql;  
  17. }  
  18.   
  19. // With conditionals (note the final parameters, required for the anonymous inner class to access them)   
  20. public String selectPersonLike(final String id, final String firstName, final String lastName) {  
  21.   return new SQL() {{  
  22.     SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");  
  23.     FROM("PERSON P");  
  24.     if (id != null) {  
  25.       WHERE("P.ID like ${id}");  
  26.     }  
  27.     if (firstName != null) {  
  28.       WHERE("P.FIRST_NAME like ${firstName}");  
  29.     }  
  30.     if (lastName != null) {  
  31.       WHERE("P.LAST_NAME like ${lastName}");  
  32.     }  
  33.     ORDER_BY("P.LAST_NAME");  
  34.   }}.toString();  
  35. }  
  36.   
  37. public String deletePersonSql() {  
  38.   return new SQL() {{  
  39.     DELETE_FROM("PERSON");  
  40.     WHERE("ID = ${id}");  
  41.   }}.toString();  
  42. }  
  43.   
  44. public String insertPersonSql() {  
  45.   return new SQL() {{  
  46.     INSERT_INTO("PERSON");  
  47.     VALUES("ID, FIRST_NAME""${id}, ${firstName}");  
  48.     VALUES("LAST_NAME""${lastName}");  
  49.   }}.toString();  
  50. }  
  51.   
  52. public String updatePersonSql() {  
  53.   return new SQL() {{  
  54.     UPDATE("PERSON");  
  55.     SET("FIRST_NAME = ${firstName}");  
  56.     WHERE("ID = ${id}");  
  57.   }}.toString();  
  58. }</SPAN>  
<span style="font-size:12px;">// 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();
}</span>

方法

描述

SELECT(String)

开始或附加SELECT子句。可以称为不止一次和参数将被追加到theSELECT条款。参数通常是一个逗号分隔的列表的列和别名,但可以是任何可以接受的驱动

SELECT_DISTINCT(String)

启动或附加到一个SELECT子句,还增加了DISTINCT关键字生成的查询。可以称为不止一次和参数将被追加到SELECT子句。参数通常是一个逗号分隔的列表的列和别名,但可以是任何可接受的驱动。

FROM(String)

启动或追加到FROM子句。可以调用超过一次,将被追加的fromClause的参数。这些参数通常是一个表名和别名,或任何可接受的驱动程序。

· JOIN(String)

· INNER_JOIN(String)

· LEFT_OUTER_JOIN(String)

RIGHT_OUTER_JOIN(String)

JOIN子句添加一个新的合适的类型,这取决于调用的方法。该参数可以包括一个标准的联接组成的列和条件下加入。

WHERE(String)

追加一个新的WHERE子句条件,并使用“AND”串连。可以多次调用,每次用and这会导致它连接新的条件。使用OR()分裂ANOR

OR()

拆分当前WHERE子句条件与OR。可以不止一次被调用,但调用不止一次在一排会产生额外的SQL

AND()

拆分当前WHERE子句条件与AND。可以不止一次被调用,但调用不止一次在一排会产生额外SQL。因为同时具有自动串连,这是一个非常罕见的使用方法,只是真正包含完整性。

GROUP_BY(String)

追加一个新的GROUP BY子句元素,串连一个逗号。可以多次调用,这会导致它连接在新的条件,每次用逗号。

HAVING(String)

追加一个新的HAVING子句条件,串连。可以多次调用,这会导致它连接新的条件下,每次用and。使用OR()分裂anOR

ORDER_BY(String)

追加一个新的ORDER BY子句元素,串连一个逗号。可以多次调用,这会导致它连接在新的条件,每次用逗号。

DELETE_FROM(String)

启动DELETE语句指定表中删除。一般来说,这应遵循​​由WHERE语句!

INSERT_INTO(String)

启动Insert语句插入到指定表。此应遵循由一个或多个VALUES()调用。

SET(String)

追加一个更新语句“SET”列表。

UPDATE(String)

始一个更新(UPDATE)语句,并指定表更新。这应遵循的一个或多个SET()调用,通常一个WHERE()调用。

VALUES(String, String)

追加的insert语句。第一个参数是要插入的列(次),第二个参数的值(s)。

4、SqlBuilder和SelectBuilder(不推荐使用)

         在3.2版本之前,我们使用了一点不同的方法,通过使用一个ThreadLocal变量来掩盖一些语言的限制,使Java的DSL的有点麻烦。然而,这种方法现在已经过时,现代框架温暖了人们使用的建设者型模式和匿名内部类,伴随这样想法。因此,SelectBuilder和的SqlBuilder类已被废弃了。
下面的方法适用,只的过时的SqlBuilder和SelectBuilder类的。

方法

描述

BEGIN()/RESET()

这些方法清除的SelectBuilderThreadLocal的状态,并准备要建一个新的语句。 BEGIN()读取最好的时候,开始一个新语句。 RESET()读取时最好清除语句在执行过程中,由于某种原因,(也许如果逻辑需要一个完全不同的说法,在某些条件下)。

SQL()

这将返回生成的SQL()和重置SelectBuilder的状态(如果START()或RESET()被调用)。因此,这种方法只能被调用一次!

        SelectBuilder和SqlBuilder类没那么神奇,但重要的是要知道他们是如何工作的。 SelectBuilder SqlBuilder使用静态导入一个ThreadLocal变量,使一个干净的语法,可以轻松地用条件交错的组合。要使用它们,你需要的静态导入是这样的(一个或另一个,但不能同时)类中的方法:

  1. <SPAN style="FONT-SIZE: 12px">import static org.apache.ibatis.jdbc.SelectBuilder.*;</SPAN>  
<span style="font-size:12px;">import static org.apache.ibatis.jdbc.SelectBuilder.*;</span>
  1. <SPAN style="FONT-SIZE: 12px">import static org.apache.ibatis.jdbc.SqlBuilder.*;</SPAN>  
<span style="font-size:12px;">import static org.apache.ibatis.jdbc.SqlBuilder.*;</span>
这使我们能够创造这样的方法:

  1. <SPAN style="FONT-SIZE: 12px">/* DEPRECATED */  
  2. public String selectBlogsSql() {  
  3.   BEGIN(); // Clears ThreadLocal variable   
  4.   SELECT("*");  
  5.   FROM("BLOG");  
  6.   return SQL();  
  7. }</SPAN>  
<span style="font-size:12px;">/* DEPRECATED */
public String selectBlogsSql() {
  BEGIN(); // Clears ThreadLocal variable
  SELECT("*");
  FROM("BLOG");
  return SQL();
}</span>
  1. <SPAN style="FONT-SIZE: 12px">/* DEPRECATED */  
  2. private String selectPersonSql() {  
  3.   BEGIN(); // Clears ThreadLocal variable   
  4.   SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME");  
  5.   SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON");  
  6.   FROM("PERSON P");  
  7.   FROM("ACCOUNT A");  
  8.   INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID");  
  9.   INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID");  
  10.   WHERE("P.ID = A.ID");  
  11.   WHERE("P.FIRST_NAME like ?");  
  12.   OR();  
  13.   WHERE("P.LAST_NAME like ?");  
  14.   GROUP_BY("P.ID");  
  15.   HAVING("P.LAST_NAME like ?");  
  16.   OR();  
  17.   HAVING("P.FIRST_NAME like ?");  
  18.   ORDER_BY("P.ID");  
  19.   ORDER_BY("P.FULL_NAME");  
  20.   return SQL();  
  21. }</SPAN>  
<span style="font-size:12px;">/* 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();
}</span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值