30分鐘入門MyBatis

顧家進發表於2019-03-03

30分鐘入門MyBatis

本文旨在用最通俗的語言講述最枯燥的基本知識

當專案框架SSH(spring Struts hibernate)日落西山時,SSM(spring SpringMVC、MyBatis)就大行其道,大部分專案都漸漸轉至SSM,因此mybatis也成了Java程式設計師的必學之術,本文就mybatis的語法做一次小小的總結,旨在讓讀者用最少的時間學會使用MyBatis。

文章提綱:

  1. 什麼是MyBatis
  2. MyBatis的引入
  3. MyBatis的初始化配置
  4. MyBatis的SQL語法
  5. 執行原理和實操一波

1. 什麼是MyBatis

MyBatis的前身是Apache的一個開源專案ibatis,後來遷移到Google code就改名為MyBatis。

用網上已經說爛了的話來說就是:

MyBatis是一款優秀的持久層框架,它支援定製化 SQL、儲存過程以及高階對映。MyBatis 避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和對映原生資訊,將介面和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java物件)對映成資料庫中的記錄。

2. MyBatis的引入

  1. 如果是傳統的的專案,則直接下載相應jar包引入到專案中即可,下載地址為:
1http://central.maven.org/maven2/org/mybatis/mybatis/3.4.6/mybatis-3.4.6.jar
複製程式碼
  1. 如果為maven構建的專案,則只需要在pom.xml中加入以下依賴然後reimport一下即可:
1<dependency>
2  <groupId>org.mybatis</groupId>
3  <artifactId>mybatis</artifactId>
4  <version>x.x.x</version>
5</dependency>
複製程式碼
  1. 如果是gradle構建的專案,則只需要在配置中新增以下程式碼:
1// https://mvnrepository.com/artifact/org.mybatis/mybatis
2compile group: 'org.mybatis', name: 'mybatis', version: '3.4.6'
複製程式碼

3. MyBatis的配置和初始化

在引入mybatis之後,接下來需要學習的mybatis的配置,雖然現在流行的框架像springboot等已經不需要用XML方式進行配置,但作為一名新手,我們還是需要學習一些關於mybatis的配置的解釋,這樣有助於我們理解mybatis的原理。
mybatis的基本配置:

 1<?xml version="1.0" encoding="UTF-8" ?>
2<!DOCTYPE configuration
3        PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

4<configuration>
5    <!--properties用於定義一些屬性變數,以便在配置檔案中呼叫-->
6    <properties>
7        <!--定義一個變數為driver的屬性,在下面就可以用${driver}來獲得其屬性值-->
8        <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
9        <property name="url" value="jdbc:mysql://10.0.0.11/test"></property>
10    </properties>
11    <!--定義不同環境下的配置,便於區分生產、測試等環節的配置-->
12    <environments default="development">
13       <!--定義一個環境下的配置-->
14        <environment id="development">
15            <transactionManager type="JDBC"/>
16            <dataSource type="POOLED">
17                <property name="driver" value="${driver}"/>
18                <property name="url" value="${url}"/>
19                <property name="username" value="root"/>
20                <property name="password" value="1111"/>
21            </dataSource>
22        </environment>
23    </environments>
24    <!--用於設定mapper檔案的引入-->
25    <mappers>
26        <!--resource方式引入mapper檔案-->
27        <mapper resource="mapper/UserMapper.xml"/>
28    </mappers>
29</configuration>
複製程式碼

這是一個標準的mybatis的配置檔案,很多情況下,這個配置已經足夠,但是為了在以後的使用有更好的認識,下面講解配置檔案中configuration標籤下的常用子標籤:

  1. properties標籤:用於定義一些通用屬性,便於配置檔案中使用
  2. settings標籤:用於設定一些改變MyBatis執行時行為的配置
  3. environments標籤:用於配置成適應多種環境
  4. mappers標籤:用於mapper對映器的設定

下面分別對每個標籤做簡單講解:

1.properties標籤

當我們需要把一些值作為一個變數被配置中使用時,就可以在properties標籤下增加一個property標籤,其中屬性name是指變數名稱,屬性value是值,如:

1 <properties>
2        <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
3 </property>
複製程式碼

定義好之後,就可以在配置檔案中使用了,如:

1<dataSource type="POOLED">
2   <property name="driver" value="${driver}"/>
3</dataSource>           
複製程式碼

2.settings標籤

settings標籤中的每一個setting都是用於調整mybatis的執行行為,我們在需要使用其中某些setting時加入即可,其常用的配置以及各個setting的解釋如下:

 1<settings>
2  #設定配置檔案中的所有對映器已經配置的任何快取,預設false。
3  <setting name="cacheEnabled" value="true"/>
4  #延遲載入的全域性開關。當開啟時,所有關聯物件都會延遲載入,預設為false
5  <setting name="lazyLoadingEnabled" value="true"/>
6  #是否允許單一語句返回多結果集,預設為true
7  <setting name="multipleResultSetsEnabled" value="true"/>
8  #是否使用列標籤代替列名,預設為true
9  <setting name="useColumnLabel" value="true"/>
10  #是否允許JDBC支援自動生成主鍵,預設為false
11  <setting name="useGeneratedKeys" value="false"/>
12  #指定 MyBatis 應如何自動對映列到欄位或屬性
13  <setting name="autoMappingBehavior" value="PARTIAL"/>
14  #指定發現自動對映目標未知列(或者未知屬性型別)的行為,預設NONE
15  #NONE: 不做任何反應
16  #WARNING: 輸出提醒日誌
17  #FAILING: 對映失敗 (丟擲 SqlSessionException)
18  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
19  #配置預設的執行器。預設為SIMPLE
20  #SIMPLE 就是普通的執行器;
21  #REUSE 執行器會重用預處理語句; 
22  #BATCH 執行器將重用語句並執行批量更新
23  <setting name="defaultExecutorType" value="SIMPLE"/>
24  #設定超時時間,它決定驅動等待資料庫響應的秒數。 
25  <setting name="defaultStatementTimeout" value="25"/>
26  #為驅動的結果集獲取數量(fetchSize)設定一個提示值  
27  <setting name="defaultFetchSize" value="100"/>
28  #是否允許在巢狀語句中使用分頁。如果允許使用則設定為false。
29  <setting name="safeRowBoundsEnabled" value="false"/>
30  #是否開啟自動駝峰命名規則(camel case)對映,預設為false
31  <setting name="mapUnderscoreToCamelCase" value="false"/>
32</settings>
複製程式碼

3. environments

environments是為了配置多環境資料來源而生,在我們定義好了各種環境之後,只需要在程式碼中設定從哪個環境中載入資料來源即可,或者修改environments標籤中的default也可以達到切換環境的效果。
environments的基本配置如下:

 1<environments default="development">
2  #定義一個名稱為development的環境配置
3  <environment id="development">
4    #設定事務管理器的型別,有JDBC和MANAGED樑總
5    <transactionManager type="JDBC">
6      <property name="..." value="..."/>
7    </transactionManager>
8    #資料來源設定
9    <dataSource type="POOLED">
10      <property name="driver" value="${driver}"/>
11      <property name="url" value="${url}"/>
12      <property name="username" value="${username}"/>
13      <property name="password" value="${password}"/>
14    </dataSource>
15  </environment>
16</environments>
複製程式碼

當我們需要增加一個環境配置時,只需要複製貼上一份environment,修改其中屬性的值即可。

4.mappers

mappers標籤實際上是用於高速mybatis從哪找到我們寫好的SQL語句,也就是對映檔案。當我們寫好一個表對應的mapper.xml時,我們只需要在mappers下增加一個mapper即可。

mappers查詢mapper的方式有多種:

1. 根據mapper.xml檔案定位:

這些mapper.xml在resources中的某個資料夾xxx中,則用resource屬性設定

1<mappers>
2<mapper resource="xxx/AMapper.xml"/>
3<mapper resource="xxx/BMapper.xml"/>
4</mappers>
複製程式碼
2. 根據對映器介面實現類的完全限定類名:

當我們在這些mapper.xml設定好了namespace之後,我們可以通過對映器介面實現類的全路徑類來設定,如在AMapper.xml設定namespace為com.xxx.dao.AMapper類之後,我們在這裡可以使用class屬性指定查詢的mapper,但前提是:
AMapper.xml和AMapper.java必須在同一個包下。

1<mappers>
2<mapper class ="com.xxx.dao.AMapper"/>
3<mapper class ="com.xxx.dao.BMapper"/>
4</mappers>
複製程式碼
3. 包對映

有人會說,如果我們表有很多,這樣一行一行的寫不是很費勁嗎,mybatis為了便於使用,提供了package的方式引入對映器,但前提
所有的mapper.xml和mapper.java必須在同一個包下。

1<mappers>
2  <package name="org.xxx.dao"/>
3</mappers>
複製程式碼

4. URL對映:

如果你的mapper不在專案中,而是放到了其他檔案內,mybatis提供了通過URL的方式引入mapper.xml。

1<mappers>
2  <mapper url="C:///test/mappers/AMapper.xml"/>
3  <mapper url="C:///test/mappers/BMapper.xml"/>
4</mappers>
複製程式碼

5. MyBatis的SQL語法

在現有的框架下編寫程式碼,多數情況下都不需要理會mybatis底層的東西,而大量的工作都集中在編寫mapper檔案上。因此學會在mybatis下編寫SQL語句是非常有必要的,我們首先來看一個標準的mapper檔案的格式:

1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3<mapper namespace="com.xxx.dao.XxxMapper">
4</mapper>
複製程式碼

可以看出,一個mapper檔案的根結構是mapper標籤開始,而mapper標籤中的namespace有什麼用呢?他應該怎麼寫?

我們知道,有一種程式設計思想叫做面向介面程式設計,就是把業務需求中具體邏輯實現和介面分開,對外只暴露介面,通過介面實現業務。而在業務需求變化時,僅需要修改實現類,而不需要變動現有的對接程式碼,降低對系統的影響。

而mybatis正是基於這樣的思想,在namespace中指定該mapper對應的介面之後,不需要編寫介面實現類,mybatis會通過該繫結自動幫你找到對應要執行的SQL語句。

如:在com.xxx.dao中建立一個XxxMapper.java的介面,需要編寫一根據使用者查詢使用者資訊的方法。

1package com.xxx.dao;
2public interface XxxMapper  {
3  //根據姓名查詢一條使用者資訊
4  Map selectUserByName(@Param("name") String name);
5}
複製程式碼

此時我們就可以在mapper.xml中設定namespace對應到上面的介面來:

1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3<mapper namespace="com.xxx.dao.XxxMapper">
4 <select id="selectUserByName" parameterType="String" resultType="hashmap">
5  select * from user where name = #{name}
6</select>
7</mapper>
複製程式碼

而在具體的業務實現類中,則是這樣使用的:

1@Service
2public class XxxServiceImpl implements CustomerInfoService {
3    @Resource
4    private  XxxMapper xxxMapper=null;
5    @Override
6    public Map getUser(String name) {
7        return xxxMapper.selectUserByName(name);
8    }
9}
複製程式碼

可以看出,從編寫SQL語句到最終業務呼叫SQL語句的過程中,我們並沒有給XxxMapper介面編寫任何的實現類,這就是基於介面程式設計的思想,mybatis已經把這些事情都處理好了,我們只需要在namespace中把SQL對映檔案和介面類對應起來,就可以使用了。

知道根節點mapper怎麼設定之後,接下來我們需要學習如何在mapper節點裡編寫SQL語句,在mapper標籤後,mybatis提供了很多語義化的標籤以便於我們編寫SQL語句和配置對映檔案,下面是幾個非常常用子標籤:

1. select:用於編寫查詢語句的標籤
2. update:用於編寫update語句的標籤
3. insert:用於編寫insert語句的標籤
4. delete:用於編寫delete語句的標籤
5. sql:編寫語句塊的標籤,可被其它語句引用
6. resultMap:定義資料庫結果和實體屬性的對映關係

這些標籤都是我們在編寫SQL語句中的必備標籤,下面一一描述他們的使用。

1. select標籤

在一個專案中,大部分功能都涉及到查詢,因此mybatis也為select元素配備了非常多的屬性,一下僅列出最常用的幾個屬性以及作用解釋:

 1<select
2  #必填,唯一識別符號,和mapper介面中的方法一一對應
3  id="selectUser"
4  #選填,預設值為 unset,用於傳入引數的型別設定
5  parameterType="String"
6  #選填,語句查詢結果返回的期望型別,resultType 和 resultMap不能同時使用
7  resultType="HashMap"
8  #選填,語句查詢結果返回的資料集,可以對應實體類和和resultMap定義的ID
9  resultMap="com.xxx.entity.User"
10  #是否清除快取,為true時本地快取和二級快取都會被清除
11  flushCache="false"
12  #是否啟用快取,為true時查詢結果會被放入二級快取
13  useCache="true"  >

14
15 #SQL語句編寫....
16
17 </select>
複製程式碼

2. update標籤

 1<update
2  #必填,唯一識別符號,和mapper介面中的方法一一對應
3  id="updateUser"
4  #選填,預設值為 unset,用於傳入引數的型別設定
5  parameterType="com.xxx.entity.User"
6  #是否清除快取,為true時本地快取和二級快取都會被清除
7  flushCache="true">

8
9 #編寫update的SQL語句...
10
11</update>
複製程式碼

3. insert標籤

 1<insert
2  #必填,唯一識別符號,和mapper介面中的方法一一對應
3  id="updateUser"
4  #選填,預設值為 unset,用於傳入引數的型別設定
5  parameterType="com.xxx.entity.User"
6  #是否清除快取,為true時本地快取和二級快取都會被清除
7  flushCache="true"
8  #是否取出由資料庫內部生成的主鍵,預設為false
9   useGeneratedKeys="false"  
10   #選填,設定了之後,會通過getGeneratedKeys的返回值或者通過 insert語句的selectKey子元素設定它的鍵值。
11   keyProperty="id"
12  >

13
14 #編寫insert的SQL語句...
15
16</insert>
複製程式碼

4. delete標籤

 1<delete
2  #必填,唯一識別符號,和mapper介面中的方法一一對應
3  id="updateUser"
4  #選填,預設值為 unset,用於傳入引數的型別設定
5  parameterType="com.xxx.entity.User"
6  #是否清除快取,為true時本地快取和二級快取都會被清除
7  flushCache="true">

8
9 #編寫delete的SQL語句...
10
11</delete>
複製程式碼

5. sql標籤

SQL節點用來編寫那些可以被重用的SQL程式碼段,當我們用SQL編寫好一個程式碼段之後,就可以在其他語句使用。

我們都知道,在寫滿了SQL之後,如果要修改表名,是一件很痛苦的事情,因為表名都寫到了SQL語句中了,但是在mybatis中,我們可以利用sql標籤來定義好表名,如果在所有的SQL中引入這個程式碼塊即可:

1<sql id="TABLE_NAME">user</sql>
2
3#在語句中用include的方式把表名動態化
4<select id="selectUserByName">
5select * from 
6<include refid="TABLE_NAME" />
7 where name = #{name}
8</select>
複製程式碼

類似的用法還有非常多,比如把查詢欄位一致的可以用sql塊統一定義,然後在需要的地方呼叫…需要我們在實際使用過程,靈活運用這些標籤來減輕SQL的程式碼量和降低複雜度。

6. resultMap標籤

resultMap標籤用於表示資料庫查詢結果和實體物件的對映關係,它是對映檔案中中所複雜的一個標籤,常用的屬性有兩個:

1 <resultMap 
2  #定義這個resultMap的唯一標識
3  id="XXXResult"
4  #返回值的全限定類名,或型別別名 
5  type="com.xxx.entity.User">
 
6
7     #子節點....
8
9  </resultMap>
複製程式碼

而它的子節點則就非常多了:

 1 <resultMap id="XXXResult" type="java.util.HashMap"> 
2    #constructor:類在例項化時,用來注入結果到構造方法中
3    <constructor>
4      #idArg:ID引數;標記結果作為ID可以幫助提高整體效能
5      <idArg/>
6      #arg:注入到構造方法的一個普通結果
7      <arg/>
8    </constructor>
9    #一個 ID 結果;標記出作為 ID 的結果可以幫助提高整體效能        
10    <id/>
11    #注入到欄位或 JavaBean 屬性的普通結果
12    <result/>
13    #一個複雜型別的關聯;許多結果將包裝成這種型別
14    <association property=""/>
15    #一個複雜型別的集合
16    <collection property=""/>
17    # 使用結果值來決定使用哪個 resultMap
18    <discriminator javaType="">
19       #基於某些值的結果對映
20       <case value=""></case>
21    </discriminator>
22  </resultMap>
複製程式碼

如查詢要把查詢結果的欄位用駝峰的寫法對映,可以定義一個resultMap,吧物件和實體屬性一一對應起來:

1<resultMap id="UserResultMap" type="java.util.HashMap">
2        <id column="id" property="id"/>
3        <result column="nick_name" property="nickName"/>
4        <result column="gmt_created" property="gmtCreated"/>
5        <result column="gmt_modified" property="gmtModified"/>
6    </resultMap>
複製程式碼

在SQL用就可以直接使用這個resultMap作為返回型別:

1<select id="selectUserByName" resultMap="UserResultMap">
2    select id,nick_name,gmt_created,gmt_modified from user where name =#{name}
3</select>
複製程式碼

上面的例子只用到resultMap中最常用的兩個子標籤: <id>、<result>。還有很多其它的標籤可以寫成高階的resultMap,由於篇幅較長,而文章旨在入門,因此在此暫不對每個標籤舉例子解釋,有興趣的可以自行百度。

6. 執行原理和實操一波

看完一波語法之後,腦子處於似懂非懂的狀態,好像都是在講配置檔案和mapper的使用。當我們學會了編寫這些mapper之後,究竟應該怎麼使用它?
到這裡我們就不得不提一下mybatis的執行過程了,先了解幾個mybatis提供的介面/類:

  1. SqlSessionFactoryBuilder : SqlSessionFactory的構造器,用於建立SqlSessionFactory,採用了Builder設計模式。
  2. SqlSessionFactory:SqlSession工廠類,以工廠形式建立SqlSession物件,採用了Factory工廠設計模式。
  3. SqlSession:執行SQL的介面

由於mybatis的執行原理非常複雜,遠遠不是30分鐘能掌握的,因此在此只是概括為最大的四個過程:

  1. 載入配置建立SqlSessionFacotry
  2. 通過sqlSessionFactory獲取SqlSession
  3. SqlSession查詢和轉化Mapper
  4. SqlSession執行mapper中的SQL語句

知道了執行流程之後,我們就可以實操一波了,雖然主流的開發框架都已經看不見這些東西了,但作者還是決定拋棄一切框架,只用maven構建一個空白專案進行實操:

  1. 在idea上建立一個maven專案,並且在pom中引入mybatis和mysql依賴

這個簡單,不多描述。
其中pom中的依賴為:

 1<dependencies>
2        <dependency>
3            <groupId>org.mybatis</groupId>
4            <artifactId>mybatis</artifactId>
5            <version>3.2.7</version>
6        </dependency>
7        <dependency>
8            <groupId>mysql</groupId>
9            <artifactId>mysql-connector-java</artifactId>
10            <version>6.0.6</version>
11        </dependency>
12    </dependencies>
複製程式碼
  1. 在resources中建立一個名為mybatis-config.xml的配置檔案,內容為:
 1<?xml version="1.0" encoding="UTF-8" ?>
2<!DOCTYPE configuration
3        PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

4<configuration>
5    <!--properties用於定義一些屬性變數,以便在配置檔案中呼叫-->
6    <properties>
7        <!--定義一個變數為driver的屬性,在下面就可以用${driver}來獲得其屬性值-->
8        <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
9        <property name="url" value="jdbc:mysql://10.9.0.111/test"></property>
10    </properties>
11    <!--定義不同環境下的配置,便於區分生產、測試等環節的配置-->
12    <environments default="development">
13       <!--定義一個環境下的配置-->
14        <environment id="development">
15            <transactionManager type="JDBC"/>
16            <dataSource type="POOLED">
17                <property name="driver" value="${driver}"/>
18                <property name="url" value="${url}"/>
19                <property name="username" value="root"/>
20                <property name="password" value="test100"/>
21            </dataSource>
22        </environment>
23    </environments>
24    <!--用於設定mapper檔案的引入-->
25    <mappers>
26        <!--resource方式引入mapper檔案-->
27        <mapper resource="mapper/UserMapper.xml"/>
28    </mappers>
29</configuration>
複製程式碼
  1. 建立表結構:
 1DROP TABLE IF EXISTS `user`;
2CREATE TABLE `user` (
3  `id` int(11NOT NULL AUTO_INCREMENT,
4  `name` varchar(255DEFAULT NULL,
5  `gmt_created` varchar(255DEFAULT NULL,
6  `gmt_modified` varchar(255DEFAULT NULL,
7  PRIMARY KEY (`id`)
8ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
9-- 插入一條數
10INSERT INTO `user` VALUES ('1''hello mybatis'nullnull);
複製程式碼
  1. 在java下建立User.java的實體類(注意:為了簡化程式碼,getter和serter已經去掉,實操時自行補上):
1public class User {
2    private Integer id;
3    private String name;
4    private String gmtCreated;
5    private String gmtModified;
6   //getter 和 setter...
7}
複製程式碼
  1. 在java下建立UserMapper.java的對映類:
1public interface UserMapper {
2    User getUserByName(@Param("name") String name);
3}
複製程式碼
  1. 在resources下建立mapper資料夾,在mapper下建立UserMapper的xml檔案:
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3<mapper namespace="UserMapper">
4    <select id="getUserByName" resultType="User">
5        select  * from  user where  name =#{name}
6    </select>
7</mapper>
複製程式碼
  1. 啟動mybatis執行SQL

根據上面的執行流程,就可以編寫一個測試類:

 1 public static  void main(String args[]){
2        try {
3            String resource = "mybatis-config.xml";
4//           1. 獲取配置檔案的輸入流
5            InputStream inputStream = Resources.getResourceAsStream(resource);
6//            2. 讀取配置檔案並用SqlSessionFactoryBuilder建立一個SqlSessionFactory
7            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
8//            3. 從SqlSessionFactory中獲取一個SqlSession
9             SqlSession s=  sqlSessionFactory.openSession();
10//             4. 查詢對映SQL檔案
11             UserMapper mapper=s.getMapper(UserMapper.class);
12//             5.執行CURD操作
13            User user=mapper.getUserByName("hello mybatis");
14
15            if(user!=null){
16                System.out.print("查詢成功,我的名次是:"+user.getName());
17            }
18
19        }catch (Exception e){
20            e.printStackTrace();
21        }
22    }
複製程式碼

檢視輸出:

1查詢成功,我的名次是:hello mybatis
複製程式碼

大功告成!有興趣的讀者可以根據上面的過程,編寫屬於自己的原生態mybatis的測試專案,如果有問題或者需要原始碼請關注公眾號留言或加微信:sisi-ceo,我們一起來征服寫程式碼這做大山~


覺得本文對你有幫助?請分享給更多人
關注「程式設計無界」,提升裝逼技能

相關文章