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)
员工 POJO 类
要执行读取操作,让我们在 Employee.java 中创建一个员工类,如下所示 −
public class Employee {
private int id;
private String first_name;
private String last_name;
private int salary;
/* 为 Employee 类定义构造函数。 */
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);
/* 这将从 Employee 表读取所有记录。*/
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 和 else 语句
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。此外,如果该内容以 AND 或 OR 开头,它知道将其删除。
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>

