前言
整理一下MyBatis中常使用的SQL說明
介紹
通過原生JDBC寫DAO的年代 ,程序員最怕莫過於拼接SQL語句,拼接參數與設置返回結果集。
Hibernate 將拼接SQL時代成爲過去,通過ORM映謝,完全不需要處理任何SQL,但這又帶來了新的問題就是。無法編寫自定義SQL從而喪失了靈活活及更好的性能。
MyBatis 通過 mapper 映射SQL很好解決了這一點,它無需在JAVA代碼中拼接SQL,而是將其移至mapper 文件集中處理SQL節約了大量的開發時間
Mapper 中的元素
元素 | 說明 |
---|---|
cache | 對給定命名空間的緩存配置 |
resultMap | 結果集映射 |
sql | 可被其他語句引用的可重用語句塊 |
insert | 插入語句 |
update | 更新語句 |
delete | 刪除語句 |
select | 查詢語句 |
常見屬性說明
<select
id="selectPerson"
<!-- 參數Java類型 -->
parameterType="int"
<!-- 參數Map類型 -->
parameterMap="paramsMap"
<!-- 返回結果java類型-->
resultType="Person"
<!-- 返回結果映射-->
resultMap="StudentMap"
<!-- 將其設置爲 true 後,只要語句被調用,都會導致本地緩存和二級緩存被清空,默認值:false -->
flushCache="false"
<!-- 將其設置爲 true 後,將會導致本條語句的結果被二級緩存緩存起來,默認值:對 select 元素爲 true。 -->
useCache="true"
<!-- 這個設置是在拋出異常之前,驅動程序等待數據庫返回請求結果的秒數。默認值爲未設置(unset)(依賴驅動) -->
timeout="10"
<!-- 是一個給驅動的提示,嘗試讓驅動程序每次批量返回的結果行數和這個設置值相等。 默認值爲未設置(unset)(依賴驅動) -->
fetchSize="256"
<!-- MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED -->
statementType="PREPARED">
</select>
StatementType詳解
類型 | 說明 | 實例 |
---|---|---|
STATEMENT | 直接執行SQL,不進行預編譯 | select * from student where id = ${id} |
PREPARED | 預處理後,執行SQL | select * from student where id = #{id} |
CALLABLE | 執行存儲過程 | {call test(#{id,jdbcType=INTEGER,mode=IN})} |
預備數據庫
如果你使用docker的話,推薦看看我的文章把 [Docker 實戰系列 - MySQL環境](…/…/Docker/實戰系列/Docker 實戰系列 - MySQL環境.md)
創建數據庫
# 創建庫
create database mybatis_demo;
創建表
CREATE TABLE `student` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`cls_id` int(10) NOT NULL COMMENT '班級ID',
`name` varchar(32) NOT NULL COMMENT '名字',
`age` int(3) NOT NULL COMMENT '年齡',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `cls` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '班級名稱',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
插入測試數據
INSERT INTO `student`(`id`, `cls_id`, `name`, `age`, `create_time`) VALUES (1, 1, '張三', 13, now());
INSERT INTO `student`(`id`, `cls_id`, `name`, `age`, `create_time`) VALUES (2, 2, '李四', 14, now());
INSERT INTO `cls`(`id`, `name`, `create_time`) VALUES (1, '初一1班', now());
INSERT INTO `cls`(`id`, `name`, `create_time`) VALUES (2, '初一2班', now());
Java類配置信息
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer id;
private String name;
private Integer clsId;
private Date createTime;
// 班級信息
private Cls cls;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cls {
private Integer id;
private String name;
}
查詢
單個簡單參數引用 方法中只有一個參數可通過任意名稱進行引用
<select id="selectStudentXml" resultMap="StudentMap">
select * from student where id = #{id}
</select>
int insertStudent(Integer clsId,String name,Integer age);
多個簡單參數引用 通過參數下標引用 #{param1} #{param2}
<insert id="insertStudent" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
INSERT INTO student(cls_id,`name`,age,create_time)
VALUES (#{param1}, #{param2}, #{param3}, now());
</insert>
int insertStudent2(Student s);
對像屬性引用: 直接通過對象屬性名稱引用,嵌套對像通過.號進行引用
<insert id="insertStudent2" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
INSERT INTO student(cls_id,`name`,age,create_time)
VALUES (#{clsId}, #{name}, #{age}, now());
</insert>
int insertStudent2(Student s);
map方式
<insert id="insertStudent3" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
INSERT INTO student(cls_id,`name`,age,create_time)
VALUES (#{clsId}, #{name}, #{age}, now());
</insert>
int insertStudent3(Map<String, Object> map);
變量名稱引用(需要jdk1.8支持) 編譯時加上-parameters
<build>
<!-- 並且在pom.xml中加入 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
關聯查詢
簡單查詢
<resultMap id="StudentMap" type="com.xm.chapter1.Student">
<id property="id" column="id"/>
<result property="clsId" column="cls_id"/>
<result property="createTime" column="create_time"/>
</resultMap>
<select id="selectStudentXml" resultMap="StudentMap">
select * from student where id = #{id}
</select>
關聯查詢 - 推薦 進行一次select
<resultMap id="StudentMap" type="com.xm.chapter1.Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="clsId" column="cls_id"/>
<result property="createTime" column="create_time"/>
<association property="cls" javaType="com.xm.chapter1.Cls">
<id property="id" column="cls_id"/>
<result property="name" column="cls_name"/>
</association>
</resultMap>
<select id="selectStudentAssociation" resultMap="StudentMap">
SELECT s.*,c.id as cls_id,c.name as cls_name from student s
left join cls c on s.cls_id = c.id
where s.id = #{id}
</select>
引入外部進行關聯查詢 - 不推薦 會進行兩次select,然後mybatis關聯
<resultMap id="StudentMap" type="com.xm.chapter1.Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="clsId" column="cls_id"/>
<result property="createTime" column="create_time"/>
<association
property="cls"
javaType="com.xm.chapter1.Cls"
select="selectByClsId" column="cls_id"/>
</resultMap>
<select id="selectStudentAssociation2" resultMap="StudentMap">
SELECT * from student where id = #{id}
</select>
動態SQL
where標籤會自動加入SQL where
,並去除無用的符號
<select id="selectWhere" resultMap="StudentMap">
SELECT * from student where id = #{id}
<where>
<if test="title != null and title != ''">
and name = #{name}
</if>
<if test="age != null">
and age = #{age}
</if>
</where>
order by id
</select>
使用when + 默認值
<select id="selectUserListSortBy" resultMap="StudentMap">
SELECT * FROM student
<choose>
<when test="sortBy == 'name' or sortBy == 'age'">
order by ${sortBy}
</when>
<!-- 不傳值,寫入這個 -->
<otherwise>
order by name
</otherwise>
</choose>
</select>
只想選擇一項,任選一。MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。
<!-- 官方寫的還可以,直接抄 -->
<select id="findActiveBlogLike"
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_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
若語句的開頭爲“AND”或“OR”,where 元素也會將它們去除
<trim prefix="WHERE" prefixOverrides="AND|OR ">
...
</trim>
刪除某尾部“AND”或“OR”,where 元素也會將它們去除
<trim prefix="WHERE" suffixOverrides="AND|OR ">
...
</trim>
update語句中的set
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update
set 元素會動態前置 SET 關鍵字,同時也會刪掉無關的逗號
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio},</if>
</set>
where id=#{id}
</update>
動態 SQL 的另外一個常用的操作需求是對一個集合進行遍歷,通常是在構建 IN 條件語句的時候。比如:
<select id="selectStudentListSortBy" resultMap="StudentMap">
SELECT * FROM student where id in
<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
#{item}
</foreach>
</select>
List<Student> selectStudentListSortBy(@Param("list") List<Integer> list);
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> code = mapper.selectStudentListSortBy(Arrays.asList(1,2,3));
System.out.println(code);
在同一個mapper 多個statement 存在多個相同的sql 片段時,可以通過<sql>
元素聲明,在通過 <include>
元素進行引用
<sql id="files">
id ,name ,createTime
</sql>
<include refid="files" />
擴展動態SQL
以上邏輯符號都是MyBatis中自帶的XMLLanguageDriver所提供的解釋語言,除非此之外我們還可以使用MyBatis-Velocity 或 mybatis-freemarker 等外部解釋器來編寫動態腳本
引入依賴
<dependency>
<groupId>org.mybatis.scripting</groupId>
<artifactId>mybatis-freemarker</artifactId>
<version>1.1.2</version>
</dependency>
定義
List<Student> selectByIds(@Param("ids") List<Integer> ids);
<select id="selectByIds"
resultMap="StudentMap"
lang="org.mybatis.scripting.freemarker.FreeMarkerLanguageDriver">
SELECT * FROM student where id in(${ids?join(',')})
</select>
查詢
@Test
public void language(){
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> code = mapper.selectByIds(Arrays.asList(1,2,3));
System.out.println(code);
}