3. MyBatis - 深度學習 - SQL語句

前言

整理一下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);
}
發佈了193 篇原創文章 · 獲贊 35 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章