iBATIS - 動態SQL



動態SQL是iBATIS的一個非常強大的功能。有時您需要根據引數物件的狀態更改WHERE子句條件。在這種情況下,iBATIS提供了一組動態SQL標籤,可用於對映語句中,以增強SQL的可重用性和靈活性。

所有邏輯都使用一些額外的標籤放在.XML檔案中。以下是一個示例,其中SELECT語句將以兩種方式工作:

  • 如果傳遞了一個ID,則它將返回與該ID對應的所有記錄。
  • 否則,它將返回所有員工ID設定為NULL的記錄。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Employee">

   <select id="findByID" resultClass="Employee">
      SELECT * FROM EMPLOYEE
		
      <dynamic prepend="WHERE ">
         <isNull property="id">
            id IS NULL
         </isNull>
			
         <isNotNull property="id">
            id = #id#
         </isNotNull>
      </dynamic>
		
   </select>
</sqlMap>

您可以使用<isNotEmpty>標籤檢查條件,如下所示。此處,僅當傳遞的屬性不為空時才會新增條件。

..................
<select id="findByID" resultClass="Employee">
   SELECT * FROM EMPLOYEE
	
   <dynamic prepend="WHERE ">
      <isNotEmpty property="id">
         id = #id#
      </isNotEmpty>
   </dynamic>
	
</select>
..................

如果您想要一個可以選擇員工ID和/或姓名的查詢,則您的SELECT語句如下所示:

..................
<select id="findByID" resultClass="Employee">
   SELECT * FROM EMPLOYEE
	
   <dynamic prepend="WHERE ">
      <isNotEmpty prepend="AND" property="id">
         id = #id#
      </isNotEmpty>
		
      <isNotEmpty prepend="OR" property="first_name">
         first_name = #first_name#
      </isNotEmpty>
   </dynamic>
</select>
..................

動態SQL示例

以下示例展示瞭如何使用動態SQL編寫SELECT語句。假設我們在MySQL中擁有以下EMPLOYEE表:

CREATE TABLE EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

假設此表只有一條記錄,如下所示:

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
|  1 | Zara       | Ali       |   5000 |
+----+------------+-----------+--------+
1 row in set (0.00 sec)

Employee POJO類

為了執行讀取操作,讓我們在Employee.java中建立一個Employee類,如下所示:

public class Employee {
   private int id;
   private String first_name; 
   private String last_name;   
   private int salary;  

   /* Define constructors for the Employee class. */
   public Employee() {}
  
   public Employee(String fname, String lname, int salary) {
      this.first_name = fname;
      this.last_name = lname;
      this.salary = salary;
   }

   /* Here are the method definitions */
   public int getId() {
      return id;
   }
	
   public String getFirstName() {
      return first_name;
   }
	
   public String getLastName() {
      return last_name;
   }
	
   public int getSalary() {
      return salary;
   }
	
} /* End of Employee */

Employee.xml檔案

為了使用iBATIS定義SQL對映語句,我們將在Employee.xml中新增以下修改後的<select>標籤,並在該標籤定義內,我們將定義一個“id”,它將在IbatisReadDy.java中用於對資料庫執行動態SQL SELECT查詢。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Employee">
   <select id="findByID" resultClass="Employee">
      SELECT * FROM EMPLOYEE
	
      <dynamic prepend="WHERE ">
         <isNotNull property="id">
            id = #id#
         </isNotNull>
      </dynamic>
		
   </select>
</sqlMap>

以上SELECT語句將以兩種方式工作:

  • 如果傳遞了一個ID,則它將返回與該ID對應的記錄;否則,它將返回所有記錄。

IbatisReadDy.java檔案

此檔案具有應用程式級邏輯,用於從Employee表讀取條件記錄:

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

import java.io.*;
import java.sql.SQLException;
import java.util.*;

public class IbatisReadDy{
   public static void main(String[] args) throws IOException,SQLException{
   
      Reader rd=Resources.getResourceAsReader("SqlMapConfig.xml");
      SqlMapClient smc=SqlMapClientBuilder.buildSqlMapClient(rd);

      /* This would read all records from the Employee table.*/
      System.out.println("Going to read records.....");
      Employee rec = new Employee();
      rec.setId(1);

      List <Employee> ems = (List<Employee>)  
         smc.queryForList("Employee.findByID", rec);
      Employee em = null;
		
      for (Employee e : ems) {
         System.out.print("  " + e.getId());
         System.out.print("  " + e.getFirstName());
         System.out.print("  " + e.getLastName());
         System.out.print("  " + e.getSalary());
         em = e; 
         System.out.println("");
      }    
      System.out.println("Records Read Successfully ");
   }
} 

編譯和執行

以下是編譯和執行上述軟體的步驟。在繼續編譯和執行之前,請確保已正確設定PATH和CLASSPATH。

  • 建立如上所示的Employee.xml。
  • 建立如上所示的Employee.java並編譯它。
  • 建立如上所示的IbatisReadDy.java並編譯它。
  • 執行IbatisReadDy二進位制檔案以執行程式。

您將獲得以下結果,並且將從EMPLOYEE表中讀取一條記錄。

Going to read records.....
   1  Zara  Ali  5000
Record Reads Successfully

嘗試將null作為smc.queryForList("Employee.findByID", null)傳遞,執行以上示例。

iBATIS OGNL表示式

iBATIS提供了強大的基於OGNL的表示式,以消除大多數其他元素。

  • if語句
  • choose、when、otherwise語句
  • where語句
  • foreach語句

if語句

在動態SQL中最常見的事情是根據條件包含where子句的一部分。例如:

<select id="findActiveBlogWithTitleLike" parameterType="Blog" resultType="Blog">
   SELECT * FROM BLOG
   WHERE state = 'ACTIVE.
	
   <if test="title != null">
      AND title like #{title}
   </if>
	
</select>

此語句提供了一種可選的文字搜尋型別功能。如果您不傳遞標題,則將返回所有活動的部落格。但是,如果您確實傳遞了一個標題,它將查詢具有給定like條件的標題。

您可以包含多個if條件,如下所示:

<select id="findActiveBlogWithTitleLike" parameterType="Blog" resultType="Blog">
   SELECT * FROM BLOG
   WHERE state = 'ACTIVE.
	
   <if test="title != null">
      AND title like #{title}
   </if>
	
   <if test="author != null">
      AND author like #{author}
   </if>
	
</select>

choose、when和otherwise語句

iBATIS提供了一個choose元素,它類似於Java的switch語句。它有助於在許多選項中只選擇一個情況。

以下示例將僅根據提供的標題進行搜尋,然後僅根據提供的作者進行搜尋。如果兩者都沒有提供,則僅返回特色部落格:

<select id="findActiveBlogWithTitleLike" parameterType="Blog" resultType="Blog">
   SELECT * FROM BLOG
   WHERE state = 'ACTIVE.
	
   <choose>
      <when test="title != null">
         AND title like #{title}
      </when>
		
      <when test="author != null and author.name != null">
         AND author like #{author}
      </when>
		
      <otherwise>
         AND featured = 1
      </otherwise>
   </choose>
	
</select>

where語句

檢視我們之前的示例,瞭解如果未滿足任何條件會發生什麼。您最終將得到如下所示的SQL:

SELECT * FROM BLOG
WHERE

這將失敗,但iBATIS有一個簡單的解決方案,只需一個簡單的更改,一切正常:

<select id="findActiveBlogLike" parameterType="Blog" resultType="Blog">
   SELECT * FROM BLOG
	
   <where>
      <if test="state != null">
         state = #{state}
      </if>
		
      <if test="title != null">
         AND title like #{title}
      </if>
		
      <if test="author != null>
         AND author like #{author}
      </if>
   </where>
	
</select>

where元素僅在包含的標籤返回任何內容時插入WHERE。此外,如果該內容以ANDOR開頭,它就知道將其去除。

foreach語句

foreach元素允許您指定一個集合並宣告可以在元素主體內部使用的項和索引變數。

它還允許您指定開始和結束字串,並在迭代之間新增分隔符。您可以構建一個IN條件,如下所示:

<select id="selectPostIn" resultType="domain.blog.Post">
   SELECT *
   FROM POST P
   WHERE ID in
	
   <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
      #{item}
   </foreach>
	
</select>
廣告