MyBatis插件開發


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】。

轉載請注明出處和鏈接地址,歡迎轉載,謝謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM