3、Mybatis核心應用配置與原理解析

1、Mybatis一二級緩存處理

知識點:算法

1 級緩存使用場景sql

2 級緩存使用場景數據庫

1. 一級緩存使用場景

訂單表與會員表是存在一對多的關係 爲了儘量減小join 查詢,進行了分階段查詢,即先查詢出訂單表,在根據member_id 字段查詢出會員表,最後進行數據整合 。若是訂單表中存在重複的member_id,就會出現不少不必的重複查詢。 針對這種狀況myBatis 經過1緩存來實現,在同一次查詢會話中若是出現相同的語句及參數,就會從緩存中取出不在走數據庫查詢。1級緩存只能做用於查詢會話中 因此也叫作會話緩存。apache

1.1 一級緩存示例:

LabelMapper mapper = session.getMapper(LabelMapper.class);
Label label = mapper.getById(23);
Label label2 = mapper.getById(23);
Label label3 = sqlSessionFactory.openSession().getMapper(LabelMapper.class).getById(23);
Label label4 = session.getMapper(Label2Mapper.class).getById(23);
System.out.println(label == label2);
System.out.println(label3 == label2);
System.out.println(label4 == label2);
複製代碼

1.2 一級緩存的使用條件

  1. 必須是相同的SQL和參數
  2. 必須是相同的會話
  3. 必須是相同的namespace即同一個mapper
  4. 必須是相同的statement即同一個mapper接口中的同一個方法
  5. 查詢語句中間沒有執行session.clearCache()方法
  6. 查詢語句中間沒有執行 insert update delete 方法(不管變更記錄是否與 緩存數據有無關係)

1.3 一級緩存源碼解析

緩存獲取:
>mapper.findById(1) dao方法
 >org.apache.ibatis.session.defaults.DefaultSqlSession#selectList()
  >org.apache.ibatis.executor.CachingExecutor#query()
   >org.apache.ibatis.executor.BaseExecutor#query() 142L
    >org.apache.ibatis.cache.impl.PerpetualCache#getObject 55L
複製代碼
緩存存儲:
>mapper.findById(1) dao方法
 >org.apache.ibatis.session.defaults.DefaultSqlSession#selectList()
  >org.apache.ibatis.executor.CachingExecutor#query()
   >org.apache.ibatis.executor.BaseExecutor#query() 142L
    >org.apache.ibatis.executor.BaseExecutor#queryFromDatabase
     >org.apache.ibatis.cache.impl.PerpetualCache#putObject
複製代碼
經過對clearCache做爲入口咱們可能追蹤到一級緩存的實現PerpetualCache
>org.apache.ibatis.session.defaults.DefaultSqlSession#clearCache
  >org.apache.ibatis.executor.CachingExecutor#clearLocalCache
     >org.apache.ibatis.executor.BaseExecutor#clearLocalCache
        >org.apache.ibatis.cache.impl.PerpetualCache#clear
複製代碼

提問:在查詢時另外一個會話併發去修改查詢的數據,一級緩存是否會生效?若是生效是否就會致使數據不正確?緩存

2. 二級緩存使用場景

業務系統中存在不少的靜態數據如,字典表、菜單表、權限表等,這些數據的特性是不會輕易修改但又是查詢的熱點數據。一級緩存針對的是同一個會話當中相同SQL,並不適合這情熱點數據的緩存場景。爲了解決這個問題引入了二級緩存,它脫離於會話以外。bash

2.1 二級緩存示例:

@CacheNamespace()
public interface LabelMapper {
    @Select("select * from t_label where id =#{id}")
    Label getById(Integer id);
}
複製代碼

屬性說明:session

@CacheNamespace(
        implementation = PerpetualCache.class, //  緩存實現 Cache接口 實現類
        eviction = LruCache.class,// 緩存算法
        flushInterval = 60000, // 刷新間隔時間 毫秒
        size = 1024,   // 最大緩存引用對象
        readWrite = true, // 是否可寫
        blocking = false  // 是否阻塞
)
複製代碼

2.2 二級緩存使用條件

  1. 當會話提交或關閉以後纔會填充二級緩存
  2. 必須是在同一個命名空間之下
  3. 必須是相同的statement 即同一個mapper 接口中的同一個方法
  4. 必須是相同的SQL語句和參數
  5. 若是readWrite=true ,實體對像必須實現Serializable 接口

2.3 二級緩存清除條件

  1. xml中配置的update 不能清空 @CacheNamespace 中的緩存數據
  2. 只有修改會話提交以後 纔會執行清空操做
  3. 任何一種增刪改操做 都會清空整個namespace 中的緩存

2.4 二級緩存源碼解析

清除緩存
>org.apache.ibatis.session.defaults.DefaultSqlSession#selectList() 147L
  >org.apache.ibatis.executor.CachingExecutor#query()81L
    >org.apache.ibatis.executor.CachingExecutor#query()95L
     >org.apache.ibatis.executor.CachingExecutor#flushCacheIfRequired() 164L //清除緩存
複製代碼
緩存緩存關鍵源碼
>org.apache.ibatis.cache.TransactionalCacheManager#getObject 
     >org.apache.ibatis.cache.decorators.TransactionalCache#getObject
      >org.apache.ibatis.cache.decorators.SynchronizedCache#getObject
       >org.apache.ibatis.cache.decorators.LoggingCache#getObject
        >org.apache.ibatis.cache.decorators.SerializedCache#getObject
         >org.apache.ibatis.cache.decorators.ScheduledCache#getObject
          >org.apache.ibatis.cache.decorators.LruCache#getObject
           >org.apache.ibatis.cache.impl.PerpetualCache#getObject
複製代碼
保存二級緩存
org.apache.ibatis.executor.CachingExecutor#close
      >org.apache.ibatis.cache.TransactionalCacheManager#commit
       >org.apache.ibatis.cache.decorators.TransactionalCache#flushPendingEntries
        >org.apache.ibatis.cache.decorators.SynchronizedCache#putObject
         >org.apache.ibatis.cache.decorators.LoggingCache#putObject
          >org.apache.ibatis.cache.decorators.SerializedCache#putObject
           >org.apache.ibatis.cache.decorators.ScheduledCache#putObject
            >org.apache.ibatis.cache.decorators.LruCache#putObject
             >org.apache.ibatis.cache.impl.PerpetualCache#putObject
複製代碼

2、Mybatis動態化SQL

基本命令使用mybatis

if
choose (when, otherwise)
trim (where, set)
foreach
複製代碼

示例說明:併發

<trim prefix="where" prefixOverrides="and|or">
    <if test="id != null">
        and id = #{id}
    </if>
    <if test="name != null">
        and name = #{name}
    </if>
</trim>
複製代碼

1. trim屬性說明:

prefix="where"   // 前綴
prefixOverrides="and|or"  // 前綴要替換的詞
suffix=""   // 添加後綴
suffixOverrides="" // 後綴要替換的詞
複製代碼

2. 元素說明:

在where 包裹的SQL前會自動添加 where 字符 並去掉首尾多佘的 and|or 字符 至關於下配置:app

<trim prefix="where" prefixOverrides="and|or" suffixOverrides="and|or"> 
複製代碼

3. 元素說明:

在set包裹的SQL前會自動添加 set 字符並去掉首尾多佘的 , 字符。

4. 元素說明:

在同一個mapper 多個statement 存在多個相同的sql 片斷時,能夠經過元素聲明,在經過 元素進行引用。

聲明sql 段

<sql id="files">
    id ,name ,createTime
</sql>
複製代碼

引用

<include refid="files" />
複製代碼

5. 變量使用

有時須要進行一些額外 邏輯運行,經過 聲明元素,並在其value 屬性中添加運算腳本,以下示例 自動給likeName 加上了% 分號,而後就能夠用#{likeName} 來使用帶%分號的like 運算。

<bind name="likeName" value="'%'+ _parameter.getName() +'%'"></bind>
複製代碼

6. 內置變量

_databaseid 數據庫標識ID _parameter 當前參數變理

7. 自定義模板解釋器

以上的if trim where 等邏輯符都是 myBatis 自帶的XMLLanguageDriver 所提供的解釋語言,除非此以外 咱們還可使用 MyBatis-Velocity 或 mybatis-freemarker 等外部 解釋器來編寫動態腳本。

mybatis-freemarker 使用

引入mybatis 包:

<dependency>
    <groupId>org.mybatis.scripting</groupId>
    <artifactId>mybatis-freemarker</artifactId>
    <version>1.1.2</version>
</dependency>
複製代碼

添加sql 語句

<select id="selectByIds"
        resultType="com.tuling.mybatis.dao.User"
        lang="org.mybatis.scripting.freemarker.FreeMarkerLanguageDriver">
    select  * from user
    where  id in(${ids?join(',')})
</select>
複製代碼

添加接口方法

List<User> selectByIds(@Param("ids") List<Integer> ids);
複製代碼
相關文章
相關標籤/搜索