11.2 基于注解的动态SQL0 项目结构

11.2 注解的使用示例5 测试动态SQL

MyBatis的注解也支持动态SQLMyBatis提供了各种注解,如@InsertProvider@UpdateProvider@DeleteProvider@SelectProvider,来帮助构建动态SQL语句,然后MyBatis可以执行这些SQL语句。

以上4个Provider注解都有

  • type属性,该属性指定了一个类。
  • method属性指定该类的方法,其用来提供需要执行的SQL语句。

SQL类

使用字符串拼接的方法构建SQL语句是非常困难的,并且容易出错。所以MyBaits提供了一个SQL工具类org.apache.ibatis.jdbc.SQL该类不使用字符串拼接的方式,并且会以合适的空格前缀和后缀来构造SQL语句。
SQL类的常用方法如下:

方法 描述
T LEFT_OUTER_JOIN(String join) JOIN子句,连接方式是左外连接(LEFT_OUTER)JOIN)。
T RIGHT_OUTER_JOIN(String join) JOIN子句,连接方式是右外连接(RIGHT_OUTER _JOIN)。
T WHERE(String conditions) 追加一个新的WHERE子句条件,可以多次调用。
T OR() 使用OR拆分当前WHERE子句条件,可以不止一次调用.
T AND() 使用AND拆分当前WHERE子句条件,可以不止一次调用。
T GROUP_BY(String columns) 追加一个新的GROUP BY子句元素。
T HAVING( String conditions) 追加一个新的 HAVING子句条件.
T ORDER_BY(String columns) 追加一个新的ORDER BY子句元素。
T INSERT_INTO(String tableName) 启动INSERT语句插入到指定表,应遵循由个或多个VALUES()调用。
T VALUES(String columns,String values) 追加的INSERT语句。第一个参数是要插入的列,第二个参数是插入的值。
T DELETE_FROM(String table) 启动DELETE语句,并指定删除表.
T UPDATE(String table) 启动一个更新(UPDATE)语句,并指定更新表。
T SET(String sets) 追加一个SET更新语句列表。
动态SQL provider方法可以接受以下参数:
  • 无参数
  • java对象
  • java.util.Map

搭建基本项目框架

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
E:\workspace_web2\MyADynamicSQLTest
├─src
│ ├─db.properties
│ ├─domain
│ │ └─Employee.java
│ ├─fractory
│ │ └─SqlSessionFactoryTools.java
│ ├─log4j.xml
│ ├─mapper
│ │ ├─EmployeeDynamicSQLProvider.java
│ │ └─EmployeeMapper.java
│ ├─mybatis-config.xml
│ ├─tb_employee.sql
│ └─test
│ ├─TestParamPO.java
│ └─TestParmMap.java
└─WebContent
└─WEB-INF
└─lib
├─commons-logging-1.2.jar
├─log4j-1.2.17.jar
├─log4j-api-2.3.jar
├─log4j-core-2.3.jar
├─mybatis-3.4.5.jar
└─mysql-connector-java-5.1.44-bin.jar

数据库表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建数据表
DROP TABLE IF EXISTS `tb_employee`;
CREATE TABLE `tb_employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`loginname` varchar(18) DEFAULT NULL,
`password` varchar(18) DEFAULT NULL,
`name` varchar(18) DEFAULT NULL,
`sex` char(2) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`phone` varchar(21) DEFAULT NULL,
`sal` double DEFAULT NULL,
`state` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# 插入数据
INSERT INTO `tb_employee` VALUES ('1', 'xiaoming', 'xiaoming', '小明', '男', '19', '123456789123', '9800', 'active');
INSERT INTO `tb_employee` VALUES ('2', 'xiaowang', 'xiaowang', '小王', '男', '19', '123456789123', '6800', 'active');
INSERT INTO `tb_employee` VALUES ('3', 'xiaoli', 'xiaoli', '小丽', '女', '23', '123456789123', '7800', 'active');
INSERT INTO `tb_employee` VALUES ('4', 'xiaofang', 'xiaofang', '小芳', '女', '22', '123456789123', '8800', 'active');

持久化对象

/MyADynamicSQLTest/src/domain/Employee.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package domain;
public class Employee {
// 员工编号
private Integer id;
// 登录名
private String loginname;
// 密码
private String password;
private String name;
private String sex;
private Integer age;
private String phone;
// 薪水
private Double sal;
// 状态
private String state;
public Employee()
{
}
public Employee(Integer id, String loginname, String password, String name, String sex,
Integer age, String phone, double sal, String state)
{
super();
this.id = id;
this.loginname = loginname;
this.password = password;
this.name = name;
this.sex = sex;
this.age = age;
this.phone = phone;
this.sal = sal;
this.state = state;
}
// 此处省略getter和setter方法,请自己补上
@Override
public String toString()
{
return "Employee [id=" + id + ", loginname=" + loginname + ", password=" + password
+ ", name=" + name + ", sex=" + sex + ", age=" + age + ", phone=" + phone + ", sal="
+ sal + ", state=" + state + "]";
}
}

工具类

/MyADynamicSQLTest/src/fractory/SqlSessionFactoryTools.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package fractory;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class SqlSessionFactoryTools {
private static SqlSessionFactory sqlSessionFactory = null;
static
{
try
{
InputStream mybatisConfigXML = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(mybatisConfigXML);
} catch (IOException e)
{
e.printStackTrace();
}
}
public static SqlSession getSqlSession()
{
return sqlSessionFactory.openSession();
}
}

mybatis相关配置文件

数据库信息属性文件db.properties

/MyADynamicSQLTest/src/db.properties
1
2
3
4
5
6
7
8
# 保存为db.properties文件,然后在mybatis-config.xml中通过下面标签引入:
# <properties resource="db.properties"/>
# 下面的标签放在mybatis-config.xml文件的environments标签的environment子标签的子标签dataSource标签中
# <property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/>
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
username=root
password=root

log4j.xml

/MyADynamicSQLTest/src/log4j.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration
PUBLIC "-//LOG4J//DTD LOG4J//EN"
"https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd" >
<!-- 请在mybatis-config.xml中配置如下设置 -->
<!-- <settings> -->
<!-- <setting -->
<!-- name="logImpl" -->
<!-- value="log4j"/> -->
<!-- </settings> -->
<log4j:configuration>
<appender
name="STDOUT"
class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param
name="ConversionPattern"
value="%5p [%t] %m%n"/>
</layout>
</appender>
<logger name="mapper.EmployeeMapper">
<level value="DEBUG"/>
</logger>
<root>
<level value="ERROR"/>
<appender-ref ref="STDOUT"/>
</root>
</log4j:configuration>

mybatis-config.xml

/MyADynamicSQLTest/src/mybatis-config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 该配置文件包含对 MyBatis 系统的核心设置 -->
<configuration>
<properties resource="db.properties" />
<settings>
<setting name="logImpl" value="log4j" />
</settings>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC" />
<dataSource type="pooled">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="mapper.EmployeeMapper" />
</mappers>
</configuration>

EmployeeMapper接口

/MyADynamicSQLTest/src/mapper/EmployeeMapper.java
1
2
3
4
package mapper;
public interface EmployeeMapper {

}

动态SQL生成器

/MyADynamicSQLTest/src/mapper/EmployeeDynamicSQLProvider.java
1
2
3
4
5
6
7
package mapper;
import java.util.Map;
import org.apache.ibatis.jdbc.SQL;
import domain.Employee;
public class EmployeeDynamicSQLProvider {

}

动态SQL方法写法

1
2
3
4
5
6
7
8
public String 方法名称(参数列表)
{
return new SQL() {
{
//动态sql语句写在这里
}
}.toString();
}

注意构造函数SQL()后面有两个嵌套的大括号,

  • 内层大括号里面写上动态SQL的生成逻辑,
  • 外层大括号后面接上.toString(),以调用toString方法生成SQL语句(字符串)