本文旨在用最通俗的語言講述最枯燥的基本知識
當專案框架SSH(spring Struts hibernate)日落西山時,SSM(spring SpringMVC、MyBatis)就大行其道,大部分專案都漸漸轉至SSM,因此mybatis也成了Java程式設計師的必學之術,本文就mybatis的語法做一次小小的總結,旨在讓讀者用最少的時間學會使用MyBatis。
文章提綱:
- 什麼是MyBatis
- MyBatis的引入
- MyBatis的初始化配置
- MyBatis的SQL語法
- 執行原理和實操一波
1. 什麼是MyBatis
MyBatis的前身是Apache的一個開源專案ibatis,後來遷移到Google code就改名為MyBatis。
用網上已經說爛了的話來說就是:
MyBatis是一款優秀的持久層框架,它支援定製化 SQL、儲存過程以及高階對映。MyBatis 避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和對映原生資訊,將介面和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java物件)對映成資料庫中的記錄。
2. MyBatis的引入
- 如果是傳統的的專案,則直接下載相應jar包引入到專案中即可,下載地址為:
1http://central.maven.org/maven2/org/mybatis/mybatis/3.4.6/mybatis-3.4.6.jar
複製程式碼
- 如果為maven構建的專案,則只需要在pom.xml中加入以下依賴然後reimport一下即可:
1<dependency>
2 <groupId>org.mybatis</groupId>
3 <artifactId>mybatis</artifactId>
4 <version>x.x.x</version>
5</dependency>
複製程式碼
- 如果是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標籤下的常用子標籤:
- properties標籤:用於定義一些通用屬性,便於配置檔案中使用
- settings標籤:用於設定一些改變MyBatis執行時行為的配置
- environments標籤:用於配置成適應多種環境
- 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提供的介面/類:
- SqlSessionFactoryBuilder : SqlSessionFactory的構造器,用於建立SqlSessionFactory,採用了Builder設計模式。
- SqlSessionFactory:SqlSession工廠類,以工廠形式建立SqlSession物件,採用了Factory工廠設計模式。
- SqlSession:執行SQL的介面
由於mybatis的執行原理非常複雜,遠遠不是30分鐘能掌握的,因此在此只是概括為最大的四個過程:
- 載入配置建立SqlSessionFacotry
- 通過sqlSessionFactory獲取SqlSession
- SqlSession查詢和轉化Mapper
- SqlSession執行mapper中的SQL語句
知道了執行流程之後,我們就可以實操一波了,雖然主流的開發框架都已經看不見這些東西了,但作者還是決定拋棄一切框架,只用maven構建一個空白專案進行實操:
- 在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>
複製程式碼
- 在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>
複製程式碼
- 建立表結構:
1DROP TABLE IF EXISTS `user`;
2CREATE TABLE `user` (
3 `id` int(11) NOT NULL AUTO_INCREMENT,
4 `name` varchar(255) DEFAULT NULL,
5 `gmt_created` varchar(255) DEFAULT NULL,
6 `gmt_modified` varchar(255) DEFAULT NULL,
7 PRIMARY KEY (`id`)
8) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
9-- 插入一條數
10INSERT INTO `user` VALUES ('1', 'hello mybatis', null, null);
複製程式碼
- 在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}
複製程式碼
- 在java下建立UserMapper.java的對映類:
1public interface UserMapper {
2 User getUserByName(@Param("name") String name);
3}
複製程式碼
- 在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>
複製程式碼
- 啟動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,我們一起來征服寫程式碼這做大山~
覺得本文對你有幫助?請分享給更多人
關注「程式設計無界」,提升裝逼技能