30分鐘入門MyBatis
本文旨在用最通俗的語言講述最枯燥的基本知識
當專案框架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 3PUBLIC "-//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//根據姓名查詢一條使用者資訊 4Map 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"> 5select * from user where name = #{name} 6</select> 7</mapper> 複製程式碼
而在具體的業務實現類中,則是這樣使用的:
1@Service 2public class XxxServiceImpl implements CustomerInfoService { 3@Resource 4privateXxxMapper xxxMapper=null; 5@Override 6public Map getUser(String name) { 7return 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介面中的方法一一對應 3id="selectUser" 4#選填,預設值為 unset,用於傳入引數的型別設定 5parameterType="String" 6#選填,語句查詢結果返回的期望型別,resultType 和 resultMap不能同時使用 7resultType="HashMap" 8#選填,語句查詢結果返回的資料集,可以對應實體類和和resultMap定義的ID。 9resultMap="com.xxx.entity.User" 10#是否清除快取,為true時本地快取和二級快取都會被清除 11flushCache="false" 12#是否啟用快取,為true時查詢結果會被放入二級快取 13useCache="true"> 14 15 #SQL語句編寫.... 16 17 </select> 複製程式碼
2. update標籤
1<update 2#必填,唯一識別符號,和mapper介面中的方法一一對應 3id="updateUser" 4#選填,預設值為 unset,用於傳入引數的型別設定 5parameterType="com.xxx.entity.User" 6#是否清除快取,為true時本地快取和二級快取都會被清除 7flushCache="true"> 8 9 #編寫update的SQL語句... 10 11</update> 複製程式碼
3. insert標籤
1<insert 2#必填,唯一識別符號,和mapper介面中的方法一一對應 3id="updateUser" 4#選填,預設值為 unset,用於傳入引數的型別設定 5parameterType="com.xxx.entity.User" 6#是否清除快取,為true時本地快取和二級快取都會被清除 7flushCache="true" 8#是否取出由資料庫內部生成的主鍵,預設為false 9useGeneratedKeys="false" 10#選填,設定了之後,會通過getGeneratedKeys的返回值或者通過 insert語句的selectKey子元素設定它的鍵值。 11keyProperty="id" 12> 13 14 #編寫insert的SQL語句... 15 16</insert> 複製程式碼
4. delete標籤
1<delete 2#必填,唯一識別符號,和mapper介面中的方法一一對應 3id="updateUser" 4#選填,預設值為 unset,用於傳入引數的型別設定 5parameterType="com.xxx.entity.User" 6#是否清除快取,為true時本地快取和二級快取都會被清除 7flushCache="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的唯一標識 3id="XXXResult" 4#返回值的全限定類名,或類型別名 5type="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"> 2select 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 3PUBLIC "-//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, 7PRIMARY 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 { 2private Integer id; 3private String name; 4private String gmtCreated; 5private String gmtModified; 6//getter 和 setter... 7} 複製程式碼
- 在java下建立UserMapper.java的對映類:
1public interface UserMapper { 2User 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"> 5select* fromuser wherename =#{name} 6</select> 7</mapper> 複製程式碼
- 啟動mybatis執行SQL
根據上面的執行流程,就可以編寫一個測試類:
1 public staticvoid main(String args[]){ 2try { 3String resource = "mybatis-config.xml"; 4//1. 獲取配置檔案的輸入流 5InputStream inputStream = Resources.getResourceAsStream(resource); 6//2. 讀取配置檔案並用SqlSessionFactoryBuilder建立一個SqlSessionFactory 7SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 8//3. 從SqlSessionFactory中獲取一個SqlSession 9SqlSession s=sqlSessionFactory.openSession(); 10//4. 查詢對映SQL檔案 11UserMapper mapper=s.getMapper(UserMapper.class); 12//5.執行CURD操作 13User user=mapper.getUserByName("hello mybatis"); 14 15if(user!=null){ 16System.out.print("查詢成功,我的名次是:"+user.getName()); 17} 18 19}catch (Exception e){ 20e.printStackTrace(); 21} 22} 複製程式碼
檢視輸出:
1查詢成功,我的名次是:hello mybatis 複製程式碼
大功告成!有興趣的讀者可以根據上面的過程,編寫屬於自己的原生態mybatis的測試專案,如果有問題或者需要原始碼請關注公眾號留言或加微信:sisi-ceo,我們一起來征服寫程式碼這做大山~
覺得本文對你有幫助?請分享給更多人
關注「程式設計無界」,提升裝逼技能
