> ### 架構圖

<br/>

<br/>
> ### `Mybatis`緩存
* **一級緩存**

* `SqlSession`將它的工作交給了`Executor`執行器這個角色來完成,負責完成對數據庫的各種操作。當創建了一個`SqlSession`對象時,`MyBatis`會為這個`SqlSession`對象創建一個新的`Executor`執行器,而緩存信息就被維護在這個`Executor`執行器中.。
* 當會話結束時,`SqlSession`對象及其內部的`Executor`對象還有`PerpetualCache`對象也一并釋放掉。
* 如果`SqlSession`調用了`close()`方法,會釋放掉一級緩存`PerpetualCache`對象,一級緩存將不可用。
* 如果`SqlSession`調用了`clearCache()`,會清空`PerpetualCache`對象中的數據,但是該對象仍可使用。
* `SqlSession`中執行了任何一個`update`操作(update()、delete()、insert()) ,都會清空`PerpetualCache`對象的數據,但是該對象可以繼續使用。
* `MyBatis`的一級緩存就是使用了簡單的`HashMap`,`MyBatis`只負責將查詢數據庫的結果存儲到緩存中去, 不會去判斷緩存存放的時間是否過長、是否過期。
* `Mybatis`默認開啟一級緩存。如果`Mybatis`與`Spring`整合了,`Spring`會自動關閉`sqlSession`。所以一級緩存也會失效。`Spring`每次查詢數據都會新建一個`sqlSession`綁定到當前線程的`ThreadLocal`,執行完查詢之后關閉`sqlSession`并情況`ThreadLocal`。
* **二級緩存**

* 當開一個會話時,一個`SqlSession`對象會使用一個`Executor`對象來完成會話操作,`MyBatis`的二級緩存機制的關鍵就是對這個`Executor`對象做文章。如果用戶配置了`"cacheEnabled=true"`,那么`MyBatis`在為`SqlSession`對象創建`Executor`對象時,會對`Executor`對象加上一個**裝飾者**:`CachingExecutor`,這時`SqlSession`使用`CachingExecutor`對象來完成操作請求。
* `CachingExecutor`對于查詢請求,會先判斷該查詢請求在`Application`級別的二級緩存中是否有緩存結果,如果有查詢結果,則直接返回緩存結果;如果緩存中沒有,再交給真正的`Executor`對象來完成查詢操作,之后`CachingExecutor`會將真正`Executor`返回的查詢結果放置到緩存中,然后在返回給用戶。
* 如果你的`MyBatis`使用了二級緩存,在執行查詢時會優先從二級緩存獲取。
* `MyBatis`對二級緩存的設計非常靈活,內部實現了一系列的`Cache`緩存實現類,并提供了各種緩存刷新策略如`LRU`,`FIFO`。`Mybatis`也支持自定義緩存如`Redis`等。
<br/>
> ### 動態`SQL`
* `if`
```xml
<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
```
* `choose, when, otherwise`
```xml
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
```
* `trim, where, set`
```xml
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
```
```xml
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
```
* `foreach`
```xml
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
```
***
參考:
[《深入理解mybatis原理》 MyBatis的一級緩存實現詳解](https://blog.csdn.net/luanlouis/article/details/41280959)
[《深入理解mybatis原理》 MyBatis的二級緩存的設計原理](https://blog.csdn.net/luanlouis/article/details/41408341)
[Mybatis的緩存](https://www.jianshu.com/p/c553169c5921)
[MyBatis的架構設計以及實例分析](http://www.cnblogs.com/KingIceMou/p/7193769.html)
- asD
- Java
- Java基礎
- Java編譯器
- 反射
- collection
- IO
- JDK
- HashMap
- ConcurrentHashMap
- LinkedHashMap
- TreeMap
- 阻塞隊列
- java語法
- String.format()
- JVM
- JVM內存、對象、類
- JVM GC
- JVM監控
- 多線程
- 基礎概念
- volatile
- synchronized
- wait_notify
- join
- lock
- ThreadLocal
- AQS
- 線程池
- Spring
- IOC
- 特性介紹
- getBean()
- creatBean()
- createBeanInstance()
- populateBean()
- AOP
- 基本概念
- Spring處理請求的過程
- 注解
- 微服務
- 服務注冊與發現
- etcd
- zk
- 大數據
- Java_spark
- 基礎知識
- Thrift
- hdfs
- 計算機網絡
- OSI七層模型
- HTTP
- SSL
- 數據庫
- Redis
- mysql
- mybatis
- sql
- 容器
- docker
- k8s
- nginx
- tomcat
- 數據結構/算法
- 排序算法
- 快排
- 插入排序
- 歸并排序
- 堆排序
- 計算時間復雜度
- leetcode
- LRU緩存
- B/B+ 樹
- 跳躍表
- 設計模式
- 單例模式
- 裝飾者模式
- 工廠模式
- 運維
- git
- 前端
- thymeleaf
- 其他
- 代碼規范
- work_project
- Interview