一、#{}和${}的區別是什麼?html
#{}是預編譯處理,${}是字符串替換。java
#{}是sql的參數佔位符,${}是Properties文件中的變量佔位符,它能夠用於標籤屬性值和sql內部,屬於靜態文本替換。程序員
Mybatis在處理#{}時,會將sql中的#{}替換爲?號,調用PreparedStatement的set方法來賦值; Mybatis在處理${}時,就是把${}替換成變量的值。redis
使用#{}能夠有效的防止SQL注入,提升系統安全性。spring
二、一般一個Xml映射文件,都會寫一個Dao接口與之對應,請問,這個Dao接口的工做原理是什麼?Dao接口裏的方法,參數不一樣時,方法能重載嗎?sql
Dao接口,就是人們常說的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法內的參數,就是傳遞給sql的參數。Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串做爲key值,可惟必定位一個MappedStatement,舉例:com.mybatis3.mappers.StudentDao.findStudentById,能夠惟一找到namespace爲com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每個<select>、<insert>、<update>、<delete>標籤,都會被解析爲一個MappedStatement對象。數據庫
Dao接口裏的方法,是不能重載的,由於是全限名+方法名的保存和尋找策略。編程
Dao接口的工做原理是JDK動態代理,Mybatis運行時會使用JDK動態代理爲Dao接口生成代理proxy對象,代理對象proxy會攔截接口方法,轉而執行MappedStatement所表明的sql,而後將sql執行結果返回。api
三、Mybatis是如何進行分頁的?分頁插件的原理是什麼?緩存
Mybatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁,而非物理分頁,能夠在sql內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可使用分頁插件來完成物理分頁。
分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的sql,而後重寫sql,根據dialect方言,添加對應的物理分頁語句和物理分頁參數。
舉例:select * from student,攔截sql後重寫爲:select t.* from (select * from student)t limit 0,10
簡述Mybatis的插件運行原理,以及如何編寫一個插件。
答:Mybatis僅能夠編寫針對ParameterHandler、ResultSetHandler、StatementHandler、Executor這4種接口的插件,Mybatis使用JDK的動態代理,爲須要攔截的接口生成代理對象以實現接口方法攔截功能,每當執行這4種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,固然,只會攔截那些你指定須要攔截的方法。
實現Mybatis的Interceptor接口並複寫intercept()方法,而後在給插件編寫註解,指定要攔截哪個接口的哪些方法便可,記住,別忘了在配置文件中配置你編寫的插件。
四、當實體類中的屬性名和表中的字段名不同 ,怎麼辦 ?
第1種: 經過在查詢的sql語句中定義字段名的別名,讓字段名的別名和實體類的屬性名一致
<select id=」selectorder」 parametertype=」int」 resultetype=」me.gacl.domain.order」> select order_id id, order_no orderno ,order_price price form orders where order_id=#{id}; </select>
第2種: 經過<resultMap>來映射字段名和實體類屬性名的一一對應的關係
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=」me.gacl.domain.order」 id=」orderresultmap」>
<!–用id屬性來映射主鍵字段–>
<id property=」id」 column=」order_id」>
<!–用result屬性來映射非主鍵字段,property爲實體類屬性名,column爲數據表中的屬性–>
<result property = 「orderno」 column =」order_no」/>
<result property=」price」 column=」order_price」 />
</reslutMap>
五、Mybatis是如何將sql執行結果封裝爲目標對象並返回的?都有哪些映射形式?
第一種是使用<resultMap>標籤,逐必定義列名和對象屬性名之間的映射關係。
第二種是使用sql列的別名功能,將列別名書寫爲對象屬性名,好比T_NAME AS NAME,對象屬性名通常是name,小寫,可是列名不區分大小寫,Mybatis會忽略列名大小寫,智能找到與之對應對象屬性名,你甚至能夠寫成T_NAME AS NaMe,Mybatis同樣能夠正常工做。
有了列名與屬性名的映射關係後,Mybatis經過反射建立對象,同時使用反射給對象的屬性逐一賦值並返回,那些找不到映射關係的屬性,是沒法完成賦值的。
六、Mybatis動態sql是作什麼的?都有哪些動態sql?能簡述一下動態sql的執行原理不?
Mybatis動態sql可讓咱們在Xml映射文件內,以標籤的形式編寫動態sql,完成邏輯判斷和動態拼接sql的功能。
Mybatis提供了9種動態sql標籤:trim|where|set|foreach|if|choose|when|otherwise|bind。
其執行原理爲,使用OGNL從sql參數對象中計算表達式的值,根據表達式的值動態拼接sql,以此來完成動態sql的功能。
七、Mybatis的Xml映射文件中,不一樣的Xml映射文件,id是否能夠重複?
不一樣的Xml映射文件,若是配置了namespace,那麼id能夠重複;若是沒有配置namespace,那麼id不能重複;畢竟namespace不是必須的,只是最佳實踐而已。
緣由就是namespace+id是做爲Map<String, MappedStatement>的key使用的,若是沒有namespace,就剩下id,那麼,id重複會致使數據互相覆蓋。有了namespace,天然id就能夠重複,namespace不一樣,namespace+id天然也就不一樣。
八、爲何說Mybatis是半自動ORM映射工具?它與全自動的區別在哪裏?
Hibernate屬於全自動ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,能夠根據對象關係模型直接獲取,因此它是全自動的。
而Mybatis在查詢關聯對象或關聯集合對象時,須要手動編寫sql來完成,因此,稱之爲半自動ORM映射工具。
九、一對1、一對多的關聯查詢 ?
<mapper namespace="com.lcb.mapping.userMapper">
<!--association 一對一關聯查詢 -->
<select id="getClass" parameterType="int" resultMap="ClassesResultMap">
select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap">
<!-- 實體類的字段名和數據表的字段名映射 -->
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<!--collection 一對多關聯查詢 -->
<select id="getClass2" parameterType="int" resultMap="ClassesResultMap2">
select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="student" ofType="com.lcb.user.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
</mapper>
十、Xml映射文件中,除了常見的select|insert|updae|delete標籤以外,還有哪些標籤?
還有不少其餘的標籤,<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上動態sql的9個標籤,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中<sql>爲sql片斷標籤,經過<include>標籤引入sql片斷,<selectKey>爲不支持自增的主鍵生成策略標籤。
十一、Mybatis是否支持延遲加載?若是支持,它的實現原理是什麼?
Mybatis僅支持association關聯對象和collection關聯集合對象的延遲加載,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置文件中,能夠配置是否啓用延遲加載lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB建立目標對象的代理對象,當調用目標方法時,進入攔截器方法,好比調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那麼就會單獨發送事先保存好的查詢關聯B對象的sql,把B查詢上來,而後調用a.setB(b),因而a的對象b屬性就有值了,接着完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。
固然了,不光是Mybatis,幾乎全部的包括Hibernate,支持延遲加載的原理都是同樣的。
十二、Mybatis都有哪些Executor執行器?它們之間的區別是什麼?
Mybatis有三種基本的Executor執行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor:每執行一次update或select,就開啓一個Statement對象,用完馬上關閉Statement對象。
ReuseExecutor:執行update或select,以sql做爲key查找Statement對象,存在就使用,不存在就建立,用完後,不關閉Statement對象,而是放置於Map<String, Statement>內,供下一次使用。簡言之,就是重複使用Statement對象。
BatchExecutor【執行批處理】:執行update(沒有select,JDBC批處理不支持select),將全部sql都添加到批處理中(addBatch()),等待統一執行(executeBatch()),它緩存了多個Statement對象,每一個Statement對象都是addBatch()完畢後,等待逐一執行executeBatch()批處理。與JDBC批處理相同。
做用範圍:Executor的這些特色,都嚴格限制在SqlSession生命週期範圍內。
指定使用哪種Executor執行器?
在Mybatis配置文件中,能夠指定默認的ExecutorType執行器類型,也能夠手動給DefaultSqlSessionFactory的建立SqlSession的方法傳遞ExecutorType類型參數。
1三、Mybatis是否能夠映射Enum枚舉類?
Mybatis能夠映射枚舉類,不單能夠映射枚舉類,Mybatis能夠映射任何對象到表的一列上。映射方式爲自定義一個TypeHandler,實現TypeHandler的setParameter()和getResult()接口方法。TypeHandler有兩個做用,一是完成從javaType至jdbcType的轉換,二是完成jdbcType至javaType的轉換,體現爲setParameter()和getResult()兩個方法,分別表明設置sql問號佔位符參數和獲取列查詢結果。
1四、Mybatis映射文件中,若是A標籤經過include引用了B標籤的內容,請問,B標籤可否定義在A標籤的後面,仍是說必須定義在A標籤的前面?
雖然Mybatis解析Xml映射文件是按照順序解析的,可是,被引用的B標籤依然能夠定義在任何地方,Mybatis均可以正確識別。
原理是,Mybatis解析A標籤,發現A標籤引用了B標籤,可是B標籤還沒有解析到,尚不存在,此時,Mybatis會將A標籤標記爲未解析狀態,而後繼續解析餘下的標籤,包含B標籤,待全部標籤解析完畢,Mybatis會從新解析那些被標記爲未解析的標籤,此時再解析A標籤時,B標籤已經存在,A標籤也就能夠正常解析完成了。
1五、簡述Mybatis的Xml映射文件和Mybatis內部數據結構之間的映射關係?
Mybatis將全部Xml配置信息都封裝到All-In-One重量級對象Configuration內部。在Xml映射文件中,<parameterMap>標籤會被解析爲ParameterMap對象,其每一個子元素會被解析爲ParameterMapping對象。<resultMap>標籤會被解析爲ResultMap對象,其每一個子元素會被解析爲ResultMapping對象。每個<select>、<insert>、<update>、<delete>標籤均會被解析爲MappedStatement對象,標籤內的sql會被解析爲BoundSql對象。
1.Mybatis比IBatis比較大的幾個改進是什麼
a.有接口綁定,包括註解綁定sql和xml綁定Sql ,
b.動態sql由原來的節點配置變成OGNL表達式,
c. 在一對一,一對多的時候引進了association,在一對多的時候引入了collection
節點,不過都是在resultMap裏面配置
2.什麼是MyBatis的接口綁定,有什麼好處
接口映射就是在IBatis中任意定義接口,而後把接口裏面的方法和SQL語句綁定,
咱們直接調用接口方法就能夠,這樣比起原來了SqlSession提供的方法咱們能夠有更加靈活的選擇和設置.
3.接口綁定有幾種實現方式,分別是怎麼實現的?
接口綁定有兩種實現方式,一種是經過註解綁定,就是在接口的方法上面加上
@Select@Update等註解裏面包含Sql語句來綁定,另一種就是經過xml裏面寫SQL來綁定,
在這種狀況下,要指定xml映射文件裏面的namespace必須爲接口的全路徑名.
4.什麼狀況下用註解綁定,什麼狀況下用xml綁定
當Sql語句比較簡單時候,用註解綁定,
當SQL語句比較複雜時候,用xml綁定,通常用xml綁定的比較多
5.MyBatis實現一對一有幾種方式?具體怎麼操做的
有聯合查詢和嵌套查詢,聯合查詢是幾個表聯合查詢,只查詢一次,
經過在resultMap裏面配置association節點配置一對一的類就能夠完成;
嵌套查詢是先查一個表,根據這個表裏面
的結果的外鍵id,去再另一個表裏面查詢數據,也是經過association配置,但另一個表
的查詢經過select屬性配置
6.MyBatis實現一對多有幾種方式,怎麼操做的
有聯合查詢和嵌套查詢,聯合查詢是幾個表聯合查詢,只查詢一次,經過在resultMap裏面配
置collection節點配置一對多的類就能夠完成;
嵌套查詢是先查一個表,根據這個表裏面的
結果的外鍵id,去再另一個表裏面查詢數據,也是經過配置collection,但另一個表的
查詢經過select節點配置
7.MyBatis裏面的動態Sql是怎麼設定的?用什麼語法?
MyBatis裏面的動態Sql通常是經過if節點來實現,經過OGNL語法來實現,可是若是要寫的完
整,必須配合where,trim節點,where節點是判斷包含節點有內容就插入where,不然不插
入,trim節點是用來判斷若是動態語句是以and 或or開始,那麼會自動把這個and或者or取
掉
8.IBatis和MyBatis在覈心處理類分別叫什麼
IBatis裏面的核心處理類交SqlMapClient,
MyBatis裏面的核心處理類叫作SqlSession
9.IBatis和MyBatis在細節上的不一樣有哪些
在sql裏面變量命名有原來的#變量# 變成了#{變量}
原來的$變量$變成了${變量},
原來在sql節點裏面的class都換名字交type
原來的queryForObject queryForList 變成了selectOne selectList
原來的別名設置在映射文件裏面放在了核心配置文件裏
10.講下MyBatis的緩存
MyBatis的緩存分爲一級緩存和二級緩存,
一級緩存放在session裏面,默認就有,二級緩存放在它的命名空間裏,默認是打開的,
使用二級緩存屬性類須要實現Serializable序列化接
口(可用來保存對象的狀態),可在它的映射文件中配置<cache/>
11.MyBatis(IBatis)的好處是什麼
ibatis把sql語句從Java源程序中獨立出來,
放在單獨的XML文件中編寫,給程序的維護帶來了很大便利。
ibatis封裝了底層JDBC API的調用細節,並能自動將結果集轉換成Java Bean對象,
大大簡化了Java數據庫編程的重複工做。
由於Ibatis須要程序員本身去編寫sql語句,
程序員能夠結合數據庫自身的特色靈活控制sql語句,
所以可以實現比hibernate等全自動orm框架更高的查詢效率,可以完成複雜查詢。.
什麼是延遲加載
resultMap中的association和collection標籤具備延遲加載的功能。
延遲加載的意思是說,在關聯查詢時,利用延遲加載,先加載主信息。使用關聯信息時再去加載關聯信息。
設置延遲加載
須要在SqlMapConfig.xml文件中,在<settings>標籤中設置下延遲加載。
lazyLoadingEnabled、aggressiveLazyLoading
設置項 |
描述 |
容許值 |
默認值 |
lazyLoadingEnabled |
全局性設置懶加載。若是設爲‘false’,則全部相關聯的都會被初始化加載。 |
true | false |
false |
aggressiveLazyLoading |
當設置爲‘true’的時候,懶加載的對象可能被任何懶屬性所有加載。不然,每一個屬性都按需加載。 |
true | false |
true |
1
2
3
4
5
6
7
8
9
10
|
<
settings
>
<
setting
name
=
"lazyLoadingEnabled"
value
=
"true"
/>
<
setting
name
=
"aggressiveLazyLoading"
value
=
"false"
/>
<
setting
name
=
"cacheEnabled"
value
=
"true"
/>
</
settings
>
|
|
什麼是查詢緩存
Mybatis的一級緩存是指SqlSession。一級緩存的做用域是一個SqlSession。Mybatis默認開啓一級緩存。
在同一個SqlSession中,執行相同的查詢SQL,第一次會去查詢數據庫,並寫到緩存中;第二次直接從緩存中取。當執行SQL時兩次查詢中間發生了增刪改操做,則SqlSession的緩存清空。
Mybatis的二級緩存是指mapper映射文件。二級緩存的做用域是同一個namespace下的mapper映射文件內容,多個SqlSession共享。Mybatis須要手動設置啓動二級緩存。
在同一個namespace下的mapper文件中,執行相同的查詢SQL,第一次會去查詢數據庫,並寫到緩存中;第二次直接從緩存中取。當執行SQL時兩次查詢中間發生了增刪改操做,則二級緩存清空。
一級緩存原理
一級緩存區域是根據SqlSession爲單位劃分的。
每次查詢會先去緩存中找,若是找不到,再去數據庫查詢,而後把結果寫到緩存中。Mybatis的內部緩存使用一個HashMap,key爲hashcode+statementId+sql語句。Value爲查詢出來的結果集映射成的java對象。
SqlSession執行insert、update、delete等操做commit後會清空該SQLSession緩存。
二級緩存原理
二級緩存是mapper級別的。Mybatis默認是沒有開啓二級緩存。
第一次調用mapper下的SQL去查詢用戶信息。查詢到的信息會存到該mapper對應的二級緩存區域內。
第二次調用相同namespace下的mapper映射文件中相同的SQL去查詢用戶信息。會去對應的二級緩存內取結果。
若是調用相同namespace下的mapper映射文件中的增刪改SQL,並執行了commit操做。此時會清空該namespace下的二級緩存。
開啓二級緩存
一、 在覈心配置文件SqlMapConfig.xml中加入如下內容(開啓二級緩存總開關):
cacheEnabled設置爲 true
二、在映射文件中,加入如下內容,開啓二級緩存:
實現序列化
因爲二級緩存的數據不必定都是存儲到內存中,它的存儲介質多種多樣,因此須要給緩存的對象執行序列化。
若是該類存在父類,那麼父類也要實現序列化。
禁用二級緩存
該statement中設置userCache=false能夠禁用當前select語句的二級緩存,即每次查詢都是去數據庫中查詢,默認狀況下是true,即該statement使用二級緩存。
刷新二級緩存
通常的咱們將Mybatis和Spring整合時,mybatis-spring包會自動分裝sqlSession,而Spring經過動態代理sqlSessionProxy使用一個模板方法封裝了select()等操做,每一次select()查詢都會自動先執行openSession(),執行完close()之後調用close()方法,至關於生成了一個新的session實例,因此咱們無需手動的去關閉這個session(),固然也沒法使用mybatis的一級緩存,也就是說mybatis的一級緩存在spring中是沒有做用的。
所以咱們通常在項目中實現Mybatis的二級緩存,雖然Mybatis自帶二級緩存功能,可是若是實在集羣環境下,使用自帶的二級緩存只是針對單個的節點,因此咱們採用分佈式的二級緩存功能。通常的緩存NoSql數據庫如redis,Mancache等,或者EhCache均可以實現,從而更好地服務tomcat集羣中ORM的查詢。
3、Cache使用時的注意事項
1. 只能在【只有單表操做】的表上使用緩存
不僅是要保證這個表在整個系統中只有單表操做,並且和該表有關的所有操做必須所有在一個namespace
下。
2. 在能夠保證查詢遠遠大於insert,update,delete操做的狀況下使用緩存
這一點不須要多說,全部人都應該清楚。記住,這一點須要保證在1的前提下才能夠!
4、避免使用二級緩存
可能會有不少人不理解這裏,二級緩存帶來的好處遠遠比不上他所隱藏的危害。
-
緩存是以namespace
爲單位的,不一樣namespace
下的操做互不影響。
-
insert,update,delete操做會清空所在namespace
下的所有緩存。
-
一般使用MyBatis Generator生成的代碼中,都是各個表獨立的,每一個表都有本身的namespace
。
爲何避免使用二級緩存
在符合【Cache使用時的注意事項】的要求時,並無什麼危害。
其餘狀況就會有不少危害了。
針對一個表的某些操做不在他獨立的namespace
下進行。
例如在UserMapper.xml
中有大多數針對user
表的操做。可是在一個XXXMapper.xml
中,還有針對user
單表的操做。
這會致使user
在兩個命名空間下的數據不一致。若是在UserMapper.xml
中作了刷新緩存的操做,在XXXMapper.xml
中緩存仍然有效,若是有針對user
的單表查詢,使用緩存的結果可能會不正確。
更危險的狀況是在XXXMapper.xml
作了insert,update,delete操做時,會致使UserMapper.xml
中的各類操做充滿未知和風險。
有關這樣單表的操做可能不常見。可是你也許想到了一種常見的狀況。
多表操做必定不能使用緩存
爲何不能?
首先無論多表操做寫到那個namespace
下,都會存在某個表不在這個namespace
下的狀況。
例如兩個表:role
和user_role
,若是我想查詢出某個用戶的所有角色role
,就必定會涉及到多表的操做。
<select id="selectUserRoles" resultType="UserRoleVO"> select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid} </select>
像上面這個查詢,你會寫到那個xml中呢??
無論是寫到RoleMapper.xml
仍是UserRoleMapper.xml
,或者是一個獨立的XxxMapper.xml
中。若是使用了二級緩存,都會致使上面這個查詢結果可能不正確。
若是你正好修改了這個用戶的角色,上面這個查詢使用緩存的時候結果就是錯的。
這點應該很容易理解。
在我看來,就以MyBatis目前的緩存方式來看是無解的。多表操做根本不能緩存。
若是你讓他們都使用同一個namespace
(經過<cache-ref>
)來避免髒數據,那就失去了緩存的意義。
看到這裏,實際上就是說,二級緩存不能用。整篇文章介紹這麼多也沒什麼用了。
5、挽救二級緩存?
想更高效率的使用二級緩存是解決不了了。
可是解決多表操做避免髒數據仍是有法解決的。解決思路就是經過攔截器判斷執行的sql涉及到那些表(能夠用jsqlparser解析),而後把相關表的緩存自動清空。可是這種方式對緩存的使用效率是很低的。
設計這樣一個插件是至關複雜的,既然我沒想着去實現,就不廢話了。
最後仍是建議,放棄二級緩存,在業務層使用可控制的緩存代替更好。
MyBatis 包含一個很是強大的查詢緩存特性,它能夠很是方便地配置和定製。緩存能夠極大的提高查詢效率。
- MyBatis系統中默認定義了兩級緩存。
- 一級緩存和二級緩存。
一、默認狀況下,只有一級緩存(SqlSession級別的緩存,也稱爲本地緩存)開啓。
二、二級緩存須要手動開啓和配置,他是基於namespace級別的緩存。
三、爲了提升擴展性。MyBatis定義了緩存接口Cache。咱們能夠經過實現Cache接口來自定義二級緩存
1、一級緩存
一級緩存(local cache), 即本地緩存, 做用域默認爲sqlSession。當 Session flush 或 close 後, 該Session 中的全部 Cache 將被清空。本地緩存不能被關閉, 但能夠調用clearCache(清空本地緩存, 或者改變緩存的做用域.在mybatis3.1以後, 能夠配置本地緩存的做用域.在 mybatis.xml 中配置
localCacheScope |
MyBatis 利用本地緩存機制(Local Cache)防止循環引用(circular references)和加速重複嵌套查詢。 默認值爲 SESSION,這種狀況下會緩存一個會話中執行的全部查詢。 若設置值爲 STATEMENT,本地會話僅用在語句執行上,對相同 SqlSession 的不一樣調用將不會共享數據。 |
2、一級緩存演示&失效狀況
同一次會話期間只要查詢過的數據都會保存在當前SqlSession的一個Map中
- key:hashCode+查詢的SqlId+編寫的sql查詢語句+參數
- 一級緩存失效的四種狀況
一、不一樣的SqlSession對應不一樣的一級緩存
二、同一個SqlSession可是查詢條件不一樣
三、同一個SqlSession兩次查詢期間執行了任何一次增刪改操做
四、同一個SqlSession兩次查詢期間手動清空了緩存
3、二級緩存
- 二級緩存(second level cache),全局做用域緩存;二級緩存默認不開啓,須要手動配置
- MyBatis提供二級緩存的接口以及實現,緩存實現要求 POJO實現Serializable接口
- 二級緩存在 SqlSession 關閉或提交以後纔會生效
使用步驟
- 全局配置文件中開啓二級緩存
- 須要使用二級緩存的映射文件處使用cache配置緩存
- 注意:POJO須要實現Serializable接口
4、緩存相關屬性
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache>
一、eviction=「FIFO」:緩存回收策略:• 默認的是 LRU。
- LRU – 最近最少使用的:移除最長時間不被使用的對象。
- FIFO – 先進先出:按對象進入緩存的順序來移除它們。
- SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
- WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
二、flushInterval:刷新間隔,單位毫秒
- 默認狀況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新
三、size:引用數目,正整數
- 表明緩存最多能夠存儲多少個對象,太大容易致使內存溢出
四、readOnly:只讀,true/false
- true:只讀緩存;會給全部調用者返回緩存對象的相同實例。所以這些對象不能被修改。這提供了很重要的性能優點。
- false:讀寫緩存;會返回緩存對象的拷貝(經過序列化)。這會慢一些,可是安全,所以默認是 false。
5、緩存有關設置
一、全局setting的cacheEnable:
二、select標籤的useCache屬性:
- 配置這個select是否使用二級緩存。一級緩存一直是使用的
三、sql標籤的flushCache屬性:
- 增刪改默認flushCache=true。sql執行之後,會同時清空一級和二級緩存。
- 查詢默認flushCache=false。
四、sqlSession.clearCache():
五、當在某一個做用域 (一級緩存Session/二級緩存Namespaces) 進行了 C/U/D 操做後,默認該做用域下全部 select 中的緩存將被clear。
6、第三方緩存整合
- EhCache 是一個純Java的進程內緩存框架,具備快速、精幹等特色,是Hibernate中默認的CacheProvider。
- MyBatis定義了Cache接口方便咱們進行自定義擴展。
- 步驟:
一、導入ehcache包,以及整合包,日誌包
ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar
slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar
二、編寫ehcache.xml配置文件
三、配置cache標籤
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
- 參照緩存:若想在命名空間中共享相同的緩存配置和實例。可使用 cache-ref 元素來引用另一個緩存。