文章目錄
什麼是動態SQL?
在MyBatis中可以存在動態SQL,那麼什麼是動態SQL呢?
動態SQL就是指根據不同的條件生成不同的SQL語句
可能還有的小夥伴不理解,那麼我就舉幾個例子,大家一看就懂了~
動態 SQL 元素和 JSTL 或基於類似 XML 的文本處理器相似。
在 MyBatis 之前的版本中,有很多元素需要花時間瞭解。
MyBatis 3 大大精簡了元素種類,現在只需學習原來一半的元素便可。
MyBatis 採用功能強大的基於 OGNL 的表達式來淘汰其它大部分元素。
if
choose (when, otherwise)
trim (where, set)
foreach
搭建環境
首先我們先創建一個基礎工程
1.創建一個數據庫並創建一張表
CREATE DATABASE `mybatis`;
USE `mybatis`;
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(30) NOT NULL COMMENT '瀏覽量'
) ENGINE=INNODB DEFAULT CHARSET=utf8
2.編寫實體類
每一個數據庫的表必定對應一個實體類
import lombok.Data;
import java.util.Date;
@Data
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private int views;
}
注意:這裏的日期的字段名create_time
和屬性名createTime
不一樣,這裏就要說一下了
因爲Java的命名規範是駝峯式命名,而Mysql中是用下劃線來分割兩個單詞的,所以我們要遵守規範來!
那麼這裏會有小夥伴說了,這個不一樣怎麼辦,會不會報錯呢?
當然,人家官方早就解決了這個問題,怎麼做嘞!
我們只需要在MyBatis的核心配置文件MyBatis_config.xml中添加以下配置就好啦~
<settings>
<!--這個就會自動將下劃線轉換成駝峯了-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3.編寫配置文件
配置文件怎麼操作具體請參考我的上一篇博客這裏就不再詳細解釋了
這裏在utils包下新建一個IDUtils類,用來生成隨機的id,因爲在實際開發中,我們不可能用1,2,3,4這些簡單的數字作爲id,id一般都是隨機生成的很長的一大串。
package com.gang.utils;
import java.util.UUID;
public class IDUtils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
}
4.編寫實體類對應Mapper接口和對應的Mapper.XML文件
BlogMapper接口
package com.gang.mapper;
import com.gang.pojo.Blog;
import java.util.List;
import java.util.Map;
public interface BlogMapper {
//裏面寫方法
int addBlog(Blog blog);
}
BlogMapper.XML連接BlogMapper接口
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 原來我們都是編寫具體的執行sql -->
<mapper namespace="com.gang.mapper.BlogMapper">
<!--這裏寫具體的SQL語句-->
<insert id="addBlog" parameterType="Blog">
insert into blog(id,title,author,create_time,views)
values (#{id},#{title},#{author},#{createDate},#{views})
</insert>
</mapper>
5.建一個測試類
注意:我們這裏使用了@Test這個註解,它可以不用寫主方法,就能運行,用來測試代碼很方便,我們要使用它,有一個前提,就是要導入junit依賴
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
怎麼導入依賴我上一篇博客也有哦~
package com.gang.mapper;
import com.gang.pojo.Blog;
import com.gang.utils.IDUtils;
import com.gang.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class BlogMapperTest {
//我們先往表裏添加點數據
@Test
public void testAddBlog(){
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
for (int i = 0; i < 5; i++) {
Blog blog = new Blog();
blog.setId(IDUtils.getId());
blog.setAuthor("範孟鋼");
blog.setCreateDate(new Date());
blog.setTitle("MyBatis入門技巧");
blog.setViews(9999);
mapper.addBlog(blog);
}
Blog blog = new Blog();
blog.setId(IDUtils.getId());
blog.setAuthor("大超");
blog.setCreateDate(new Date());
blog.setTitle("Javaweb入門技巧");
blog.setViews(9999);
mapper.addBlog(blog);
Blog blog1 = new Blog();
blog1.setId(IDUtils.getId());
blog1.setAuthor("範孟鋼");
blog1.setCreateDate(new Date());
blog1.setTitle("Mysql入門技巧");
blog1.setViews(9999);
mapper.addBlog(blog1);
Blog blog2 = new Blog();
blog2.setId(IDUtils.getId());
blog2.setAuthor("大超");
blog2.setCreateDate(new Date());
blog2.setTitle("微服務入門技巧");
blog2.setViews(9999);
mapper.addBlog(blog2);
Blog blog3 = new Blog();
blog3.setId(IDUtils.getId());
blog3.setAuthor("大超");
blog3.setCreateDate(new Date());
blog3.setTitle("大數據入門技巧");
blog3.setViews(9999);
mapper.addBlog(blog3);
}
//提交事務
session.commit();
}
注意:增刪改一定要開啓事務!不然會導致程序運行成功了,但是數據庫沒啥變化!
好,運行程序,這幾條數據就被插進去了。
有了數據之後,我們就可以玩一下這個動態SQL了
瞭解動態SQL
if(帶你理解動態SQL)
在接口中編寫如下方法(我這裏就不寫整個類了,太麻煩,沒必要,大家能看懂就行)
//通過作者名和博客名來查詢,如果作者名爲null,則根據博客名來查
//就是說這裏的條件是可以做選擇的
List<Blog> getBlogByIf(Map map);
//這裏使用參數爲Map,就是不知道我們要傳幾個參數,就設爲Map,我們想傳幾個都可以
xml配置文件中執行以下sql語句,是不是和以前寫的sql語句有點不一樣呢?
<!--
如果我們要拼接where條件,又不希望客戶端傳來的信息是錯誤的(比如說傳遞空值,就是map爲空)
這就需要更加智能的where標籤了
<where> </where>
如果後面有語句(傳入不爲空)就會自動加上where 如果後面語句的開頭是and或者or,它會自動去掉
if標籤表示條件判斷
原來的sql : select * from blog
where title = #{title} and author = #{author}
if標籤注意後面的and,不要忘了
-->
<select id="getBlogByIf" parameterType="map" resultType="Blog">
select * from blog
<where>
<if test="title!=null">
title = #{title}
</if>
<if test="author!=null">
and author = #{author}
</if>
</where>
</select>
在測試類中進行測試
①我們兩個參數都傳入
@Test
public void testGetBlogByIf() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title", "MyBatis入門技巧");
map.put("author", "範孟鋼");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
看結果
②我們只傳入作者這個參數
@Test
public void testGetBlogByIf() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
//map.put("title", "MyBatis入門技巧");
map.put("author", "範孟鋼");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
看結果
③我們只傳入博客名一個參數
@Test
public void testGetBlogByIf() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title", "MyBatis入門技巧");
//map.put("author", "範孟鋼");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
看結果
④這次我們不傳任何參數
@Test
public void testGetBlogByIf() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
//map.put("title", "MyBatis入門技巧");
//map.put("author", "範孟鋼");
List<Blog> blogByIf = mapper.getBlogByIf(map);
for (Blog blog : blogByIf) {
System.out.println(blog);
}
}
看結果
到這裏你會發現,我們明明只寫了一個SQL語句,爲什麼它會根據我們輸入的參數不同而去執行不同的SQL語句呢?
所謂的動態SQL,本質還是SQL語句 , 只是我們可以在SQL層面,去執行一個邏輯代碼
注意(要想看到這些執行的具體的SQL,就要打開日誌,我上篇博客也有)
好了,大家是否已經理解動態SQL了呢?
接下來我們再學學其他的一些標籤
trim (where,set)
where標籤上面已經講過了,這裏講一下set標籤
好,編寫如下方法
在這裏插入代碼片
編寫sql
<!--
set標籤重點注意後面的 逗號, 最後一句沒有逗號
它會動態前置set關鍵字,也可以給你智能的去掉逗號
原來的sql: update blog
set title = #{title},author = #{author}
where id = #{id}
-->
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="title!=null">
title = #{title},
</if>
<if test="author!=null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
測試方法
①傳入id和title
@Test
public void testUpdateSet() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("id","78f5b3cced7d4a5e92131039f6388d8a");
map.put("title","論一個優秀打野的自我修養");
mapper.updateBlog(map);
session.commit();
}
看結果
②傳入id和作者
@Test
public void testUpdateSet() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("id","78f5b3cced7d4a5e92131039f6388d8a");
//map.put("title","論一個優秀打野的自我修養");
map.put("author","韓信");
mapper.updateBlog(map);
session.commit();
}
看結果
③id和其他兩個都傳
@Test
public void testUpdateSet() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("id","78f5b3cced7d4a5e92131039f6388d8a");
map.put("title","一隻野怪的內心獨白");
map.put("author","藍buff");
mapper.updateBlog(map);
session.commit();
}
看結果
set和where的底層都是一個標籤trim
這個是where標籤的真面目
<trim prefix="WHERE" prefixOverrides="AND|OR">
...
</trim>
前面的查詢sql可以改爲這個
<select id="getBlogByIf" resultType="Blog" parameterType="map">
select * from blog
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="title!=null">
title = #{title}
</if>
<if test="author!=null">
and author = #{author}
</if>
</trim>
</select>
這個是set標籤的原型
<trim prefix="set" suffixOverrides=",">
...
</trim>
前面的更新sql可以改爲這個
<update id="updateBlog" parameterType="map">
update blog
<trim prefix="set" suffixOverrides=",">
<if test="title!=null">
title = #{title},
</if>
<if test="author!=null">
author = #{author}
</if>
</trim>
where id = #{id}
</update>
choose (when, otherwise)
接口方法
//查詢博客,有一個條件滿足即可
List<Blog> getBlogByChoose(Map map);
SQL語句
<!--choose好比Java中的switch標籤,只能選擇一個-->
<select id="getBlogByChoose" parameterType="map" resultType="Blog">
select * from blog
<where>
<choose>
<when test="title!=null">
title = #{title}
</when>
<when test="author!=null">
and author = #{author}
</when>
<otherwise>
<!--什麼都不傳就走這個,相當於defalut-->
and views = #{views}
</otherwise>
</choose>
</where>
</select>
測試方法
①啥都不傳
@Test
public void testChoose() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
List<Blog> blogByChoose = mapper.getBlogByChoose(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
②傳一個作者author
@Test
public void testChoose() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("author","範孟鋼");
List<Blog> blogByChoose = mapper.getBlogByChoose(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
③傳一個博客名title
@Test
public void testChoose() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title","一隻野怪的內心獨白");
List<Blog> blogByChoose = mapper.getBlogByChoose(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
④兩個都傳
@Test
public void testChoose() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, String> map = new HashMap<String, String>();
map.put("title","一隻野怪的內心獨白");
map.put("author","範孟鋼");
List<Blog> blogByChoose = mapper.getBlogByChoose(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
注意看了
怎麼和第三種情況一樣呢?說明choose標籤只能進一個條件,就和Java中switch語句一樣,進了一個條件後面的都不看了!
Foreach
寫如下接口方法
List<Blog> getBlogByForeach(Map map);
SQL語句
<!--sql() 子查詢 where in (1,2,3)
collection中是傳進來的參數集合
item是collection中參數的遍歷,就拿到每一個,並且可以直接在foreach標籤中使用
他是這樣拼接的 select * from blog where and (id=1 or id=2 or id=3)
open是開頭 separator是分割的 在每個中間 close是結束
-->
<select id="getBlogByForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
測試方法
@Test
public void testForEach() {
SqlSession session = MyBatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String,List> map = new HashMap<String, List>();
List<String> ids = new ArrayList<String>();
ids.add("78f5b3cced7d4a5e92131039f6388d8a");
ids.add("151f3db24ba24a4f8092849a1e221da0");
ids.add("80a7578f55c5403c8986bf409b3f8d51");
map.put("ids",ids);
List<Blog> blogByChoose = mapper.getBlogByForeach(map);
for (Blog blog : blogByChoose) {
System.out.println(blog);
}
}
說了這麼多
動態SQL就是用這些標籤在拼接SQL語句,我們只要保證SQL的正確性,按照SQL的格式,去排列組合就可以了
不知道還有小夥伴沒看明白嘛 揮揮~