MyBatis插件開發
一、前言
MyBatis在四大對象的創建過程中,都會有插件進行介入。插件可以利用動態代理機制一層層的包裝目標對象,而實現在目標對象執行目標方法之前進行攔截的效果。
MyBatis 允許在已映射語句執行過程中的某一點進行攔截調用。
默認情況下,MyBatis 允許使用插件來攔截的方法調用包括:
①Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
②ParameterHandler(getParameterObject, setParameters)
③ResultSetHandler(handleResultSets, handleOutputParameters)
④StatementHandler(prepare, parameterize, batch, update, query)
二、插件開發
編寫插件實現Interceptor接口,並使用@Intercepts注解完成插件簽名

在全局配置文件中注冊插件

插件原理
按照插件注解聲明,按照插件配置順序調用插件plugin方法,生成被攔截對象的動態代理
多個插件依次生成目標對象的代理對象,層層包裹,先聲明的先包裹;形成代理鏈
目標方法執行時依次從外到內執行插件的intercept方法。

多個插件情況下,我們往往需要在某個插件中分離出目標對象。可以借助MyBatis提供的SystemMetaObject類來進行獲取最后一層的h以及target屬性的值
Interceptor接口
Intercept:攔截目標方法執行
plugin:生成動態代理對象,可以使用MyBatis提供的Plugin類的wrap方法
setProperties:注入插件配置時設置的屬性

常用代碼:從代理鏈中分離真實被代理對象
//1、分離代理對象。由於會形成多次代理,所以需要通過一個while循環分離出最終被代理對象,從而方便提取信息
MetaObject metaObject = SystemMetaObject.forObject(target);
while(metaObject.hasGetter("h")) {
Object h = metaObject.getValue("h");
metaObject = SystemMetaObject.forObject(h);
}
//2、獲取到代理對象中包含的被代理的真實對象
Object obj = metaObject.getValue("target");
//3、獲取被代理對象的MetaObject方便進行信息提取
MetaObject forObject = SystemMetaObject.forObject(obj);
三、MyBatis實用場景
PageHelper插件進行分頁
批量操作
存儲過程
typeHandler處理枚舉
PageHelper插件進行分頁
PageHelper是MyBatis中非常方便的第三方分頁插件。
官方文檔:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/README_zh.md
我們可以對照官方文檔的說明,快速的使用插件:
1、導入相關包pagehelper-x.x.x.jar和jsqlparser-0.9.5.jar。
2、在MyBatis全局配置文件中配置分頁插件。

3、使用PageHelper提供的方法進行分頁
4、可以使用更強大的PageInfo封裝返回結果
批量操作
默認的openSession() 方法沒有參數,它會創建有如下特性的:
①會開啟一個事務(也就是不自動提交)
②連接對象會從由活動環境配置的數據源實例得到。
③事務隔離級別將會使用驅動或數據源的默認設置。
④預處理語句不會被復用,也不會批量處理更新。
openSession 方法的ExecutorType類型的參數,枚舉類型:
①ExecutorType.SIMPLE: 這個執行器類型不做特殊的事情(這是默認裝配的)。它為每個語句的執行創建一個新的預處理語句。
②ExecutorType.REUSE: 這個執行器類型會復用預處理語句。
③ExecutorType.BATCH: 這個執行器會批量執行所有更新語句

批量操作我們是使用MyBatis提供的BatchExecutor進行的,他的底層就是通過jdbc攢sql的方式進行的。我們可以讓他攢夠一定數量后發給數據庫一次。
publicvoidtest01() {
SqlSession openSession = build.openSession(ExecutorType.BATCH);
UserDao mapper = openSession.getMapper(UserDao.class);
longstart = System.currentTimeMillis();
for(inti = 0; i < 1000000; i++) {
String name = UUID.randomUUID().toString().substring(0, 5);
mapper.addUser(newUser(null, name, 13));
}
openSession.commit();
openSession.close();
longend = System.currentTimeMillis();
System.out.println("耗時時間:"+(end-start));
}
100萬記錄添加測試結果:消耗時間:75583
與Spring整合中,我們推薦,額外的配置一個可以專門用來執行批量操作的sqlSession
需要用到批量操作的時候,我們可以注入配置的這個批量SqlSession。通過他獲取到mapper映射器進行操作。

注意:
1、批量操作是在session.commit()以后才發送sql語句給數據庫進行執行的
2、如果我們想讓其提前執行,以方便后續可能的查詢操作獲取數據,我們可以使用sqlSession.flushStatements()方法,讓其直接沖刷到數據庫進行執行。
存儲過程
實際開發中,我們通常也會寫一些存儲過程,MyBatis也支持對存儲過程的調用
一個最簡單的存儲過程
delimiter $$
create procedure test()
begin
select 'hello';
end $$
delimiter ;
存儲過程的調用
1、select標簽中statementType=“CALLABLE”
2、標簽體中調用語法:{call procedure_name(#{param1_info},#{param2_info})}
存儲過程-游標處理:MyBatis對存儲過程的游標提供了一個JdbcType=CURSOR的支持,可以智能的把游標讀取到的數據,映射到我們聲明的結果集中
調用實例:


publicclassPageEmp {
private int start;
private int end;
private int count;
private List<Emp> emps;
<environment id="oracle_dev">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${orcl.driver}" />
<property name="url" value="${orcl.url}" />
<property name="username" value="${orcl.username}" />
<property name="password" value="${orcl.password}" />
</dataSource>
</environment>
orcl.driver=oracle.jdbc.OracleDriver
orcl.url=jdbc:oracle:thin:@localhost:1521:orcl
orcl.username=scott
orcl.password=123456
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>

自定義TypeHandler處理枚舉
我們可以通過自定義TypeHandler的形式來在設置參數或者取出結果集的時候自定義參數封裝策略:
①實現TypeHandler接口或者繼承BaseTypeHandler
②使用@MappedTypes定義處理的java類型,使用@MappedJdbcTypes定義jdbcType類型
③在自定義結果集標簽或者參數處理的時候聲明使用自定義TypeHandler進行處理,或者在全局配置TypeHandler要處理的javaType
測試實例:一個代表部門狀態的枚舉類

1、測試全局配置EnumOrdinalTypeHandler


2、測試全局配置EnumTypeHandler


3、測試參數位置設置自定義TypeHandler


自定義TypeHandler


如果,您對我的這篇博文有什么疑問,歡迎評論區留言,大家互相討論學習。
如果,您認為閱讀這篇博客讓您有些收獲,不妨點擊一下右下角的【推薦】。
如果,您希望更容易地發現我的新博客,不妨點擊一下左下角的【關注我】。
如果,您對我的博文感興趣,可以關注我的后續博客,我是【AlbertRui】。轉載請注明出處和鏈接地址,歡迎轉載,謝謝!
