Ibatis 简明教程

iBATIS - Dynamic SQL

动态 SQL 是 iBATIS 中一项非常强大的功能。有时,您不得不在根据您的参数对象的状态更改 WHERE 子句条件。在这种情况下,iBATIS 提供了一组动态 SQL 标签,可在映射的语句中使用,以增强 SQL 的可重用性和灵活性。

所有逻辑都使用一些其他标签放入 .XML 文件中。以下是一个 SELECT 语句将以两种方式工作的示例:

  1. 如果您传递一个 ID,它将返回对应于该 ID 的所有记录。

  2. 否则,它将返回所有员工 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 和/或一个 Employee 的第一个名称,您的 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>
..................

Dynamic SQL Example

以下示例显示了如何使用动态 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 Class

为了执行读取操作,让我们在 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 File

为了使用 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 语句将以两种方式工作 −

  1. 如果您传递一个 ID,那么它会返回与该 ID 对应的记录,否则,它会返回所有记录。

IbatisReadDy.java File

此文件具有应用程序级别的逻辑,用于从 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 ");
   }
}

Compilation and Run

以下是编译和运行上述软件的步骤。在继续编译和执行之前,请确保已正确设置 PATH 和 CLASSPATH。

  1. 按上述方式创建 Employee.xml。

  2. 按上述方式创建 Employee.java 并对其进行编译。

  3. 照上面所示创建 IbatisReadDy.java,并对其进行编译。

  4. 执行 IbatisReadDy 二进制文件来运行该程序。

您将得到以下结果,并且会从 EMPLOYEE 表中读取一条记录。

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

通过传递 null 作为 smc.queryForList("Employee.findByID", null) 来尝试上面的示例。

iBATIS OGNL Expressions

iBATIS 提供了强大的基于 OGNL 的表达式,以消除大多数其他元素。

  1. if Statement

  2. choose, when, otherwise Statement

  3. where Statement

  4. foreach Statement

The if Statement

在动态 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>

The choose, when, and otherwise Statements

iBATIS 提供了一个 choose 元素,类似于 Java 的 switch 语句。它有助于在许多选项中只选择一个 case。

以下示例只根据标题进行搜索(如果提供了标题的话),然后根据给定的作者进行搜索。如果没有提供标题或作者,它只返回精选的博客 −

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

The where Statement

查看我们之前的示例,看看没有满足任何条件时会发生什么。您最终将得到一条类似这样的 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。此外,如果该内容以 AND 或 OR 开头,它知道要剔除它。

The foreach Statement

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>