动态SQL就是可以根据条件动态地添加SQL语句
数据库建立测试表Blog
mysql> CREATE TABLE blog(
-> id VARCHAR(50) NOT NULL COMMENT '博客id',
-> title VARCHAR(100) NOT NULL COMMENT '博客标题',
-> author VARCHAR(30) NOT NULL COMMENT '博客作者',
-> create_time DATETIME NOT NULL COMMENT '创建时间',
-> views INT NOT NULL COMMENT '浏览量'
-> )ENGINE=InnoDB DEFAULT CHARSET = utf8;
Query OK, 0 rows affected, 1 warning (0.21 sec)
建立实体类Blog
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private int views;
插入测试数据
mysql> SELECT * FROM blog;
+----------------------------------+------------------------------+--------+---------------------+-------+
| id | title | author | create_time | views |
+----------------------------------+------------------------------+--------+---------------------+-------+
| 1457779e8d7a4a1e80e188ee59af852f | MyBatis从入门到入土 | Cap | 2020-07-09 20:13:33 | 100 |
| fe4d963daae8464fa12df800da731cbb | Spring从入门到入土 | Cap | 2020-07-09 20:21:01 | 20000 |
| ec89d3fb78f84f4b8179bb03c9761b59 | SpringMVC从入门到入土 | Cap | 2020-07-09 20:21:01 | 5 |
| 03679b21b7434cefa4a8c05369965c0f | SpringBoot从入门到入土 | Cap | 2020-07-09 20:21:01 | 99999 |
+----------------------------------+------------------------------+--------+---------------------+-------+
4 rows in set (0.02 sec)
if
结构为:
BlogMapping
接口添加一个测试if
的方法public interface BlogMapping {
List<Blog> queryBlogIF(Map map);
}
<select id="queryBlogIF" resultType="blog" parameterType="map">
SELECT *
FROM blog
WHERE 1 = 1
<if test=" title != null ">
AND title = #{title}
if>
select>
@org.junit.Test
public void test1(){
SqlSession sqlSession = MyBatisUtils.getSqlSession(true);
BlogMapping mapper = sqlSession.getMapper(BlogMapping.class);
Map map = new HashMap();
List<Blog> blogs = mapper.queryBlogIF(map);
for(Blog blog : blogs){
System.out.println(blog);
}
}
这里我们没有传入title
,所以
条件不成立,日志输出为:
Preparing: SELECT * FROM blog WHERE 1 = 1
当我们传入title
的时候
map.put("title","MyBatis从入门到入土");
日志输出:
==> Preparing: SELECT * FROM blog WHERE 1 = 1 AND title = ?
可以看到
条件成立,它将SQL语句拼接上去
在上一小节中,我们使用where 1 = 1
来避免动态SQL拼接的问题,其实MyBatis有一个更好的解决方案,那就是使用where
元素
where
元素只会在子元素返回任何内容的情况下才插入 “WHERE
” 子句。而且,若子句的开头为 “AND
” 或 “OR
”,where
元素也会将它们去除。(比如动态SQL语句拼接后为 WHERE AND title = ?
,where元素会将其变成WHERE title = ?
)
改造一下:
<select id="queryBlogIF" resultType="blog" parameterType="map">
SELECT *
FROM blog
<where>
<if test=" title != null ">
AND title = #{title}
if>
where>
select>
choose
元素会顺序选择一个条件成立的when
元素,如果没有的话会从other
元素中去取(如果有other
元素的话)
choose
的格式为:
<choose>
<when test="expr1">
when>
<when test="expr1">
when>
choose>
在接口`BlogMapping`接口添加一个测试`choose`的方法
```java
List<Blog> queryBlogChoose(Map map);
<select id="queryBlogChoose" resultType="blog" parameterType="map">
SELECT *
FROM blog
<where>
<choose>
<when test="title != null">
title = #{title}
when>
<when test="author != null">
AND author = #{author}
when>
<otherwise>
AND views = #{views}
otherwise>
choose>
where>
select>
我们在构建IN条件语句的时候,传入的值是不确定的,通过foreach可以循环遍历一个集合来遍历传入IN条件语句的值。
blog
的id
字段mysql> SELECT * FROM blog;
+----+------------------------------+--------+---------------------+-------+
| id | title | author | create_time | views |
+----+------------------------------+--------+---------------------+-------+
| 1 | MyBatis从入门到入土 | Cap | 2020-07-09 20:13:33 | 100 |
| 2 | Spring从入门到入土 | Cap | 2020-07-09 20:21:01 | 20000 |
| 3 | SpringMVC从入门到入土 | Cap | 2020-07-09 20:21:01 | 5 |
| 4 | SpringBoot从入门到入土 | Cap | 2020-07-09 20:21:01 | 99999 |
+----+------------------------------+--------+---------------------+-------+
4 rows in set (0.00 sec)
List<Blog> queryBlogForeach(List<String> list);
<select id="queryBlogForeach" resultType="blog" parameterType="list">
SELECT *
FROM blog
WHERE id IN
<foreach collection="list" index="index" item="item"
open="(" separator="," close=")">
#{item}
foreach>
select>
collection
:传入的可迭代的对象index
:当前迭代的序号item
:当前迭代获得的值,当item
是一个对象时,可以通过#{item.property}
来取到对象的属性值
index
和item
是用来在动态SQL语句中使用的
@org.junit.Test
public void test3(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapping mapper = sqlSession.getMapper(BlogMapping.class);
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
mapper.queryBlogForeach(list);
sqlSession.close();
}
运行得到
==> Preparing: SELECT * FROM blog WHERE id IN ( ? , ? , ? )
==> Parameters: 1(String), 2(String), 3(String)
<== Columns: id, title, author, create_time, views
<== Row: 1, MyBatis从入门到入土, Cap, 2020-07-09 20:13:33, 100
<== Row: 2, Spring从入门到入土, Cap, 2020-07-09 20:21:01, 20000
<== Row: 3, SpringMVC从入门到入土, Cap, 2020-07-09 20:21:01, 5
<== Total: 3
SQL片段用于复用动态SQL代码
SQL片段的格式如下:
<sql id="sqlid_name">
sql>
引用时:
<include refid="sqlid_name" />
例子,假设我们原先queryBlogIF
动态SQL语句为
<select id="queryBlogIF" resultType="blog" parameterType="map">
SELECT *
FROM blog
<where>
<if test=" title != null ">
AND title = #{title}
if>
<if test=" author != null" >
AND author = #{author}
if>
where>
select>
现在我们抽取if
<sql id="if-title-author" >
<if test=" title != null ">
AND title = #{title}
</if>
<if test=" author != null" >
AND author = #{author}
</if>
</sql>
再修改queryBlogIF
<select id="queryBlogIF" resultType="blog" parameterType="map">
SELECT *
FROM blog
<where>
<include refid="if-title-author" />
where>
select>
现在除了queryBlogIF
能够使用外,其他地方也能够引用
这样就实现了SQL片段的复用。