mybatis介紹–基於個人學習JavaWeb的使用
- 2022 年 3 月 11 日
- 筆記
- JAVA, 大二下學習的javaweb
mybatis介紹
該博文放在javaWeb系列下,目的是記錄我們javaWeb階段所學的知識 @time=2022/3/11/11:52(最近休息玩了兩天,今天重新啟動生活)
一.mybatis發展和背景介紹
1.背景知識
官網://mybatis.org/mybatis-3/zh/index.html
MyBatis本是apache的一個開源項目iBatis,2010年這個項目由apache software foundation遷移到了[google code](//baike.baidu.com/item/google code/2346604),並且改名為MyBatis。2013年11月遷移到Github。
iBATIS一詞來源於「internet」和「abatis」的組合,是一個基於Java的持久層框架。iBATIS提供的持久層框架包括SQL Maps和Data Access Objects(DAOs)。
—-百度百科
正是因為mybatis的前身是ibatis,所以在idea下import庫的時候都是 import org.apache.ibatis.*等文件
2.三層架構
分層式設計是最常見也是最重要的一種結構,微軟推薦的分層結構一般分為三層,從下至上分別為:數據訪問層(DAO層),服務邏輯層(service層),表現層(action層),三層架構和MVC架構設計是不同的,目前我個人做的東西少,還沒有體會出來這二者有什麼區別。
程式碼分層是為了讓程式碼結構更加清楚,還可以使項目分工更加明確,可讀性大大提升,更加有利於後期的維護和升級,另外一個很重要的作用是降低耦合度,程式碼後期修改更加方便。

引出一個問題,關於異常在這些層中拋出的問題,也就是每個層得到的異常究竟應該如何拋出,例如我們底層DAO層遇到的大多是資料庫操作的異常,對於這些異常,我們通常使用捕獲拋出,try{}catch(SQLException e){throw new Exception(e.message())},在表示層我們捕獲之後,使用不同的頁面來提示用戶錯誤,而不應該直接讓用戶看見DAO層的訪問錯誤。
3.優點
- 支援普通的SQL查詢
- 高級映射
- 存儲過程
- 消除了幾乎所有的jdbc程式碼和參數的手工設置以及結果集的檢索
- 支援快取機制
- xml配置簡單可用,根據介面生成對於的查詢類
硬編碼(英語:Hard Code 或 Hard Coding )是指在軟體實現上,將輸出或輸入的相關參數(例如:路徑、輸出的形式或格式)直接以常量的方式撰寫在源程式碼中,而非在運行期間由外界指定的設置、資源、數據或格式做出適當回應。一般被認定是種反模式或不完美的實現。
二.mybatis具體使用
1.配置文件的使用
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"//mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--解釋點1:-->
<!--這個setting開啟將sql中有下劃線的名字映射為駝峰命名法命名的類屬性,Camel的意思是駝峰命名法-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="JDK_LOGGING"/>
</settings>
<!--下面這個是掃描一個包中的類。給包中的所有類都起別名,別名是類名的首字母小寫(java規定所有的類名字都要大寫)-->
<typeAliases>
<package name="mybatis.entity"/>
</typeAliases>
<!--alias起別名,給自己常用的類起別名,在mapper中就可以直接使用別名了,這是單獨的寫法-->
<!-- <typeAliases >-->
<!-- <typeAlias type="mybatis.entity.User" alias="lbwnb"/>-->
<!-- </typeAliases>-->
<!--解釋點2-->
<!--enviroments設置的開發環境,目前是開發環境development,我們可以定義另外一個環境-->
<environments default="development">
<environment id="development">
<!--事務管理器-->
<transactionManager type="JDBC">
<!--中間可以寫properties屬性,但是這裡使用的是默認的jdbc-->
</transactionManager>
<!--數據源,pooled池化-->
<dataSource type="POOLED">
<!--讀取配置自動連接-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--&等於&-->
<property name="url" value="jdbc:mysql://localhost:3306/school?&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="011013"/>
</dataSource>
</environment>
<!--另外一套環境是start,雖然這裡配置是這樣的,但是我們可以在創建sqlsessionfactory的時候,我們給傳進去第二個參數,可以指定環境-->
<environment id="start">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--讀取配置自動連接-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--&等於&-->
<property name="url" value="jdbc:mysql://localhost:3306/school?&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="011013"/>
</dataSource>
</environment>
</environments>
<!--解釋點3-->
<mappers>
<!--但是值得注意的是不能重複註冊-->
<!--mapper映射的多種細節詳細去見官網說明:class是通過將 單個 的映射器介面註冊為,後續就會使用register去實現-->
<!-- <mapper class="mybatis.mapper.TestMapper"></mapper>-->
<!--package是將一個包內所有的介面都給註冊-->
<package name="mybatis.mapper"/>
</mappers>
</configuration>
在xml配置文件中,標籤對的順序必須按照:
的順序進行,否則會提示報錯。
解釋點1:關於xml配置文件中setting的設置等資訊(挑選幾個重要的)
| 設置名 | 描述 | 取值 | 默認值 |
|---|---|---|---|
| cacheEnabled | 全局性的開啟或者關閉所有映射器配置文件中已經配置的任何快取 | true/false | false |
| logImpl | mybatis的日誌是否開啟 | JDK_LOGGING ,LOG4J等 | 無 |
| mapUnderscoreToCamelCase | 對於資料庫的下換線欄位名是否映射為駝峰命名法 | true/false | false |
解釋點2:關於environment的解釋
MyBatis 可以配置成適應多種環境,這種機制有助於將 SQL 映射應用於多種資料庫之中,現實情況下有多種理由需要這麼做。例如,開發、測試和生產環境需要有不同的配置;或者想在具有相同 Schema 的多個生產資料庫中使用相同的 SQL 映射。還有許多類似的使用場景。
不過我們需要記住的,每個sqlsessionfactory只能對應一個環境,也就是說,兩個環境就要使用兩個sqlsessionfactory。 每個資料庫對應一個 SqlSessionFactory 實例
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
解釋點3:查找映射器

我當時學習對於完全限定資源定位符產生了很大的疑惑,目前我個人反正很難使用file這個url通過相對路徑找到xml配置文件,不喜歡用
2.mapper.xml文件
注意在xml中的類名如果要直接使用需要提前在config文件中配置別名屬性,我們之後才可以直接使用類名而不是使用包名
select語句
<select id='selectStu' parameterType='int' resultType='Stu'>
select * from stu where stu.id=#{id}/*這裡沒有寫分號*/
</select>
-
id這裡是為查詢語句起的名字,之後有兩種使用方式 一種是定義對於介面命名的時候起的介面函數名字是這個id,將二者綁定,另外一種方式是,在sqlsession直接使用方法
-
parameterType是指定下面參數的類型,不建議填寫,根據動態傳入的參數類型作為判定
-
resultType是返回值的實體類型
預編譯參數兩種寫法:#{}和${} #{}是使用PreparedStatement進行預編譯,可以有效防止sql注入,${}是使用Statement進行處理
insert語句
<!--插入操作-->
<insert id="addUser">
insert into user values(#{username},#{pw})
</insert>
delete語句
<delete id="deleteUser">
/*建議在這裡寫預編譯的參數的時候,名稱都和你後面要傳的實體類中的屬性名相同,不然無法完成對應,通過屬性名稱來傳遞過去*/
delete from user where username = #{username};
</delete>
update
<update id="??">
update xxx set xxx.id=1 where xxx.id = #{}
</update>
這裡除了select其他的幾個語句返回值都是int代表affect rows
強大的resultMap
在實際情況中,我們可能會遇到複雜的查詢,例如:
SELECT * from stu inner join teach on(teach.sid =stu.sid) inner join teacher on (teacher.tid=teach.tid) where teacher.tid = #{tid}
這樣產生的一個teacher類中,含有集合類類型Stus,我們通過普通的映射,無法將結果集映射為一個實體類,我們需要通過resultMap來保證映射過程的正確性:
<resultMap id="reM1" type="teacher">
<!--子元素id代表resultMap的主鍵,而result代表其屬性。也就是顯性的標註出主鍵,那麼這裡我們其實也可以使用result,id有用,尤其是應用到快取和內嵌的結果映射-->
<!--id標籤用於在多條件記錄中辨別是否為同一個對象的數據,查詢語句得到的結果中,tid相同的鑒別為同一個對象的數據,這樣下面的collection才會生效-->
<id column="tid" property="tid"/>
<result column="tname" property="tname"/>
<!--讓collection指向我們需要一對多的類型,這裡是stu,然後將我們的屬性指向它,oftype好像是在集合中用的-->
<collection property="Students" ofType="stu">
<id property="sid" column="sid"/>
<result column="sname" property="sname"/>
</collection>
</resultMap>
通過配置resultMap,另外在select查詢中指定出匹配的map,就可以實現具體的功能。
<select id='select1' resultMap='reM1' resultType='Teacher'>
SELECT * from stu inner join teach on(teach.sid =stu.sid) inner join teacher on (teacher.tid=teach.tid) where teacher.tid = #{tid}
</select>
下面是resultMap標籤中的所有可以選擇的標籤值,這裡我只使用過其中的一部分

具體講解可以查看官網的介紹//mybatis.org/mybatis-3/zh/sqlmap-xml.html
我只說幾個我能用到的:
constructor構造
將我們結果集中的數據通過指定的方式注入到實體類的相應的構造方法中去(@DATA註解生成的JavaBean只有默認的構造方式)
對於構造方法:
public class User {
//...
public User(Integer id, String username, int age) {
//...
}
//...
}
可以使用構造標籤
<constructor>
<idArg column="id" javaType="int"/>
<arg column="username" javaType="String"/>
<arg column="age" javaType="_int"/>/*這裡int包裝類和基本類intjavaType是不一樣的*/
</constructor>
這裡是按照默認的順序去傳遞參數到構造方法中,(也就是並不會按照結果集的名字和匹配)
如果我們想要把結果集的id傳給實體類的age,可以這樣
<constructor>
<idArg column="id" javaType="int" name="age" />
<arg column="age" javaType="_int" name="id" />
<arg column="username" javaType="String" name="username" />/*name參數是實體類的屬性*/
</constructor>
collection和上面演示的相同,是在一對多的時候,表示如何將多個對象映射成為集合類,存儲在一個實體類中
association代表多對一的映射,表明如何將一個對象(例如教師)映映射給許多的學生中去
快取cache
MyBatis 內置了一個強大的事務性查詢快取機制,它可以非常方便地配置和訂製。為了使它更加強大而且易於配置,我們對 MyBatis 3 中的快取實現進行了許多改進。
默認情況下,只啟用了本地的會話快取,它僅僅對一個會話中的數據進行快取。要啟用全局的二級快取,需要在SQL映射中添加一句

默認情況下,mybatis只開啟了一級快取,例如下面的例子
try(SqlSession sqlSession1=MybatisUnits.getSqlSession(true))
{
UnionSearch mapper1 = sqlSession1.getMapper(UnionSearch.class);
t1 = mapper1.getTeacherById("1");
t2=mapper1.getTeacherById("1");
System.out.println(t1==t2);//判斷地址是否相同,得到true,在同一個會話下,我們得到的數據是被快取的
}
驗證是否開啟二級快取:
Teacher t1,t2;
try(SqlSession sqlSession1=MybatisUnits.getSqlSession(true))
{
UnionSearch mapper1 = sqlSession1.getMapper(UnionSearch.class);
t1 = mapper1.getTeacherById("1");
}
try(SqlSession sqlSession2=MybatisUnits.getSqlSession(true))
{
UnionSearch mapper2 = sqlSession2.getMapper(UnionSearch.class);
t2 = mapper2.getTeacherById("1");
}
System.out.println(t1==t2);//得到false,知道二級快取是關閉的
開啟二級快取需要在mapper.xml文件下填寫相應的內容:
<cache eviction="FIFO" flushInterval="6000" size="512" readOnly="true"/>
-
eviction:清除快取的規則,有下面的幾個數值:
-
LRU– 最近最少使用:移除最長時間不被使用的對象。 -
FIFO– 先進先出:按對象進入快取的順序來移除它們。 -
SOFT– 軟引用:基於垃圾回收器狀態和軟引用規則移除對象。 -
WEAK– 弱引用:更積極地基於垃圾收集器狀態和弱引用規則移除對象。
-
-
flushInterval:間隔多長時間刷新一次,單位是毫秒
-
size是快取的大小,單位是(官網沒說,我個人覺得是mb),默認是1024
-
readOnly:設置是否只讀,默認false,設置為true會在多執行緒下更加安全,但是速度會更加的慢
3.動態SQL
官網文檔://mybatis.org/mybatis-3/zh/dynamic-sql.html
沒有用過,說不出來啥,個人理解是為了方便動態的拼接SQL使用的,中間可以添加我們傳入參數的判斷。
4.日誌
//mybatis.org/mybatis-3/zh/logging.html,可以使用配置文件設置,只用過標準輸出日誌和文件輸出的日誌。
反倒是lombok的日誌常用點。
三.mybatis的進階
1.動態代理
//www.cnblogs.com/sword-successful/p/10164864.html,我自己對於代理模式搞的不是特別清楚。
2.使用介面開發
mybatis支援映射的方式有三種(我自己知道的)
- 使用mapper.xml開發
- 使用註解配合介面開發
- 使用以上兩種配合開發
下面我們來說一下使用註解配合介面開發
查@Select
@Select("select * from stu where stu.id=#{id}")
public stu getSutById(int id);
ps:這裡需要注意的是有了兩個參數的的時候需要這樣寫
@Select("select * from stu wherr stu.name=#{name} and stu.sex=#{sex}")
publci stu getStuByParameter(@Param('name') String name,@Param('sex') String sex);
通過註解來指定上下文參數對應關係
增@insert
刪@delete
改@update
以上三個我就不詳細寫了
@Results
對應xml文件中的ResultMap,下面我們寫一個示例來演示上面說過的老師對應多個學生
@Options(useCache = false,flushCache = Options.FlushCachePolicy.TRUE)
//使用註解來完成複雜查詢
@Results(id = "reM1",{
@Result(id=true ,column = "tid",property = "tid"),
@Result(column = "tname",property = "tname"),
@Result(column = "tid",property = "Students",many = @Many(
select = "getStuByTid"
))
})
@Select("SELECT * from teacher where tid=#{tid}")
Teacher getTeacherBO(String tid);
這裡記不住的,到時候使用可以在查找,記住@result中的幾個屬性就行了,分別是column對應的是結果集中的欄位名,property是返回類中的屬性名。
many=@Many{ select=”方法名” }是一對多的使用,分別使用我們指定的 column=’id’傳入到getStuById中返回相應數據,組合稱為Students這個屬性。
我們還可以看見@Results(id = “reM1″)這個id屬性,我們同樣可以在一個方法前加入註解:@ResultMap(id=”reM1”)來指定一個使用註解的ResultMap或者xml中的ResultMap。
@option
@option選項是載入一些可選項,例如打開快取等等,使用的不多,我就不多叭叭了
優缺點:
使用介面註解的優點:
- 比較方便,快速編寫映射語句
使用介面註解的缺點:
-
適用於比較簡單的配置,當太複雜了介面就搞不定了。
-
不能使用動態SQL,有點雞肋。



