那些你必須知道的MyBatis實用知識點
一、MyBatis簡介
MyBatis的前身是Apache的一個開源專案iBatis,2010年這個專案由apache software foundation 遷移到了google code,並且改名為MyBatis。2013年11月遷移到GitHub,因此目前MyBatis是由GitHub維護的。
同樣作為持久層框架的Hibernate在前些年非常的火,它在配置了對映檔案和資料庫連線檔案後就可以通過Session操作,它甚至提供了HQL去操作POJO進而操作資料庫的資料,幾乎可以使程式設計人員脫離sql語言。可是為什麼MyBatis卻越來越受歡迎呢?我們稍稍總結如下:
Hibernate:
-
1.不方便的全表對映,比如更新時需要傳送所有的欄位;
-
2.無法根據不同的條件組裝不同sql;
-
3.對多表關聯和複製sql查詢支援較差;
-
4.有HQL但效能較差,做不到sql優化;
-
5.不能有效支援儲存過程;
在當今的大型網際網路中,靈活、sql優化,減少資料的傳遞是最基本的優化方法,但是Hibernate卻無法滿足我們的需求,而MyBatis提供了更靈活、更方便的方法。在MyBatis裡,我們需要自己編寫sql,雖然比Hibernate配置要多,但是是MyBatis可以配置動態sql,也可以優化sql,且支援儲存過程,MyBatis幾乎能做到 JDBC 所能做到的所有事情!憑藉其高度靈活、可優化、易維護等特點,成為目前大型移動網際網路專案的首選框架。
二:開發環境、流程及生命週期
1.開發環境
1.1 匯入依賴jar包
-
匯入mybatis的jar包,如果採用Maven進行部署,只需匯入mybatis座標。
-
匯入資料庫驅動jar包或座標。
-
程式碼除錯階段可匯入日誌工具jar包或座標,如log4j。
-
匯入Junit單元測試座標。
1.2 建立mybatis的主配置檔案
在resources目錄下建立一個名字為mybatis-config.xml(名稱隨意)配置檔案,編寫所需配置資訊。
1.3 準備實體類和表結構
遵循開發規範:
-
類屬性命名儘量和表字段保持一致。
-
實體類實現序列化介面。
-
實體類屬性使用包裝型別定義,如Integer。
Tips:有時可以考慮通過定義時初始化來避免可能的空指標異常!
如:private List<String> list = new ArrayList<>() ;
1.4 建立Mapper介面(Dao介面)建立介面方法和sql對映檔案
建立Mapper介面,在內定義CRUD方法。
Tips: 方法名唯一,需要在對應的mapper.xml檔案中配置id。
在resources下建立sql對映檔案。
Tips: 同對應的Mapper介面保持包結構及命名一致。
如:Mapper介面: cn.dintalk.dao.UserMapper
對應配置檔案:cn.dintalk.dao.UserMapper.xml
1.5 將對映檔案加入到mybatis主配置檔案中
將對映檔案通過引入的方式加入到mybatis的主配置檔案中。
Tips: 所有對映檔案會隨主配置檔案在程式執行時加入記憶體,任一對映檔案出 錯都會導致整個環境報錯!(初學者經常搞混resultType和resultMap)。
1.6 編寫程式碼進行CRUD操作
在對映檔案中編寫sql進行crud操作,在單元測試中,或service層中呼叫方法!
2.開發流程
環境搭建好後開發基本流程為:
-
介面定義方法 。
-
Mapper.xml檔案中編寫sql。
-
單元測試或service呼叫。
Tips: 介面中方法名稱和Mapper.xml檔案中sql語句的id保持一致!
3.生命週期
MyBatis的核心元件:
-
SqlSessionFactoryBuilder(構造器):根據配置資訊或程式碼生成SqlSessionFactory
-
SqlSessionFactory(工廠介面):依靠工廠來生成SqlSession(會話)。
-
SqlSession(會話): 既可以發生sql去執行並返回結果,也可以獲取Mapper的介面
-
SQL Mapper:它是MyBatis新設計的元件,它是由一個java介面和xml檔案(或註解)構成的,需要給出對應的sql和對映規則。它負責傳送sql去執行,並返回結果。
正確理解並掌握上述核心元件的生命週期可以讓我們寫出高效的程式,還可避免帶來嚴重的併發問題。
3.1 SqlSessionFactoryBuilder
其作用就是利用xml或java編碼獲得資源來構建SqlSessionFactory物件,構建成功就失去了存在的意義,將其回收。所以它的生命週期只存在於方法的區域性。
3.2 SqlSessionFactory
SqlSessionFactory的作用是建立SqlSession,而SqlSession就是一個會話,相當於JDBC中的Connection物件,每次訪問資料庫都需要通過SqlSessionFactory建立SqlSession,所以SqlSessionFactory應該在MyBatis應用的整個生命週期中。我們使每一個數據庫只對應一個SqlSessionFactory(單例模式)。
3.3 SqlSession
SqlSession是一個會話,相當於JDBC的一個Connection物件,它的生命週期應該是在請求資料庫處理事務的過程中。是一個執行緒不安全的物件,涉及多執行緒時格外當心。此外,每次建立的SqlSession都必須及時關閉它。
3.4 Mapper
Mapper是一個介面,沒有任何實現類,其作用是傳送sql,返回我們需要的結果,或者執行sql修改資料庫資料,因此它也因該在一個SqlSession事務方法之內,是一個方法級別的東西。就如同 JDBC中的一條sql語句的執行,它的最大範圍和SqlSession是相同的。
Tips: 根據核心元件封裝工具、形成SqlSession使用模板
public class MyBatisUtil { private static SqlSessionFactory build =null; static { try {//使用MyBatis的Resources載入資源獲得輸入流,構建工廠 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); build = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { throw new RuntimeException("資原始檔載入失敗!"); } } //使用工廠生產sqlSession public static SqlSession openSession(){ return build.openSession(); } }
SqlSession使用方法
//1.定義sqlSession SqlSession sqlSession = null; try { sqlSession = openSession(); //2.獲取對映器 UserMapper mapper = sqlSession.getMapper(UserMapper.class); //3.some code like 'User u = mapper.findById(id);' //4.sqlSession不提交預設回滾!增刪改需格外注意! sqlSession.commit(); } catch (Exception e) { throw new RuntimeException(e); } finally { if (sqlSession != null) { sqlSession.close(); } }
三:對映器
1.對映器元素簡介
我們可以在對映器中定義哪些元素,以及它們有何作用呢?
元素名稱 | 作用 |
---|---|
insert | 定義插入語句 |
delete | 定義刪除語句 |
update | 定義修改語句 |
select | 定義查詢語句 |
parameterMap | 定義引數對映關係 |
resultMap | 提供從資料庫結果集到POJO對映規則 |
cache | 配置當前名稱空間的快取配置(二級快取) |
sql | 定義部分sql,各個地方都可引用 |
cache-ref | 引用其他名稱空間的快取配置 |
在各個元素當中又有相當多的屬性配置項,這裡不多贅述,通過下一節掌握常用的內容即可。這裡特別說明sql元素的使用:
<sql id="user_columns"><!-- 此處定義後,處處使用,尤其欄位多的時候 --> id, name, password </sql> <select ....> select <include refid="user_columns"/> from users where uid=#{id} </select>
2.簡單CRUD操作
2.1新增使用者
<!-- 1.新增使用者 --> <insert id="add" parameterType="User"> INSERT into users (name,password) VALUES (#{name},#{password}); </insert>
2.2新增使用者並返回資料庫中的主鍵
<!-- 2.新增使用者,獲取資料庫生成的主鍵值(需資料庫具備主鍵自增功能) --> <insert id="add" parameterType="User" useGeneratedKeys="true" keyProperty="uid"> insert into users (name,password) values(#{name},#{password}); </insert> <!-- 3.新增使用者,獲取資料庫生成的主鍵:資料庫有無自動增長能力都可以--> <insert id="add" parameterType="User"> <selectKey keyColumn="uid" keyProperty="uid" resultType="int" order="AFTER"> select last_insert_id(); </selectKey> insert into users (name,password) values(#{name},#{password}); </insert>
2.3修改/刪除使用者
<!-- 4.修改/刪除使用者 --> <update id="update" parameterType="User"> update users set name=#{name},password=#{password} where uid=#{uid}; </update> <delete id="delete" > delete from users where uid=#{uid}; </delete>
2.4查詢使用者
<!-- 5.查詢所有的使用者 --> <!-- 定義查詢結果對映規則(結果集對映可以用別名) --> <resultMap id="userMap" type="User"> <id column="id" property="uid"></id> <result column="姓名" property="name"></result> <result column="password" property="password"></result> </resultMap> <!-- 查詢語句 --> <select id="findAll" resultMap="userMap"> select uid as id,name as '姓名',password from users; </select> <!--6.根據使用者id查詢使用者(單個引數)--> <select id="findById" parameterType="int" resultType="User"> select uid,name,password from users where uid=#{uid}; </select> <!-- 7.根據使用者名稱和密碼查詢使用者(介面定義方法引數時@Param(" ")進行指定,否則多個引數時 預設使用 arg0,arg1或param1,param2來對映) --> <select id="findByNamePassword" resultType="User"> select uid,name,password from users where name=#{name} and password=#{password}; </select> <!-- 8.根據使用者實體物件查詢使用者 --> <select id="findByUser" parameterType="User" resultType="User"> select uid,name,password from users where name=#{name}; </select> <!-- 9.根據使用者名稱進行模糊查詢 --> <select id="findUsersLikeName" resultType="User"> select uid,name,password from users where name like concat("%",#{name},"%"); </select>
四:動態sql和高階查詢
1.動態sql
MyBatis的動態sql包含這些元素:if | choose(when ohterwise) |trim(where set) | foreach ,通過這些元素來動態組裝sql語句,主要是增改查操作。* (實際開發中,嚴禁使用select * 操作。這裡為了簡便使用select演示)!
1.1使用 if,實現動態sql,完成查詢操作
<!-- 1.使用if,實現動態sql,完成查詢操作 --> <select id="findByCondition" parameterType="user" resultType="user"> select uid,name,password,email from users where 1 = 1 <if test="name != null and name !=''"> and name like concat("%",#{name},"%") </if> <if test="password != null and password != '' "> and password = #{password} </if> </select>
1.2使用if,實現動態sql,完成更新操作
<!-- 2.使用if,實現動態sql,完成更新操作 --> <update id="updateUser" parameterType="user"> update users set <if test="name != null and name != '' "> name=#{name}, </if> <if test="password != null and password != '' "> password=#{password}, </if> uid=#{uid} where uid=#{uid}; <!-- 保證任何情況下的sql完整 --> </update>
1.3使用if,實現動態sql,完成新增操作
<!-- 3.使用if,實現動態sql,完成新增操作 --> <insert id="addUser" parameterType="user"> insert into users (name, <if test="password != null and password != '' "> password, </if>email,phoneNumber,birthday) values(#{name}, <if test="password != null and password != '' "> #{password}, </if>#{email},#{phoneNumber},#{birthday}); </insert>
1.4使用choose when otherwise,實現動態sql,完成查詢操作
<!-- 4.使用choose when otherwise,實現動態sql,完成查詢操作 --> <select id="findByCondition" parameterType="user" resultType="user"> select * from users where 1 = 1 <!-- 動態組裝準備 --> <choose> <when test="name != null and name != '' "> and name like concat("%",#{name},"%"); </when> <otherwise> and 1 = 2; <!-- 動態否決 --> </otherwise> </choose> </select>
1.5使用if和where,實現動態sql,完成查詢操作 ★★★
<!-- 5.使用if和where,實現動態sql,完成查詢操作 --> <select id="findByCondition" resultType="user" parameterType="user"> select * from users <where><!-- 至少有一個if執行時才會加上where關鍵字並去掉緊跟後面的and|or關鍵字 --> <if test="name != null and name != '' "> and name like concat("%",#{name},"%") </if> <if test="password != null and password != '' "> and password=#{password} </if> </where> </select>
1.6使用if和set,實現動態sql,完成更新操作 ★★
<!-- 6.使用if和set,實現動態sql,完成更新操作 --> <update id="updateUser" parameterType="user"> update users <set><!-- set元素會去掉最後一個,號 --> <if test="name != null and name != '' "> name=#{name}, </if> <if test="password != null and password != '' "> password=#{password}, </if> uid=#{uid}, </set> where uid=#{uid}; </update> <!-- trim元素的使用 --> <trim prefix="where" prefixOverrides="and|or"></trim> <!-- 等同與where元素 --> <trim prefix="set" suffixOverrides=","></trim> <!-- 等同與set元素 -->
1.7使用foreach,實現動態sql,完成根據id集合、陣列等的查詢操作
<!-- 7.使用foreach,實現動態sql,完成根據id list列表的查詢操作 --> <select id="findByIds" resultType="user"> select * from users where uid in <foreach collection="collection" open="(" close=")" separator="," item="uid"> #{uid} </foreach> </select> <!-- foreach中的collection值取決於要遍歷的物件型別(mybatis內部做判斷後預設的) List : 可取 collection或list Set: 取 collection Array: 取 array Map: 取 _parameter(用map無意義,遍歷的依舊是value) 上述預設引用都可以在介面方法中通過@Param(“”)覆蓋掉! -->
1.8bind元素
bind元素的作用是通過OGNL表示式自定義一個上下文變數,這樣更方便我們使用。在進行模糊查詢的時候,如果是MySQL資料庫,我們常用concat函式用“%”和引數連線。然而在Oracle資料則是用連線符號“||”。這樣sql就需要提供兩種形式去實現。用bind元素,我們就不必使用資料庫語言,只要使用MyBatis的語言即可與所需引數相連。
<select id="findByCondition" parameterType="user" resultType="user"> <!-- 使用bind定義上下文變數 --> <bind name="pattern" value="'%' + name + '%' "/> select uid,name,password,email from users where 1 = 1 <if test="name != null and name !=''"> <!-- and name like concat("%",#{name},"%") --> and name like #{pattern} </if> <if test="password != null and password != '' "> and password = #{password} </if> </select>
2.高階查詢(多表查詢)
2.1一對多關聯查詢
<!-- 1.使用多表查詢,完成一對多關聯查詢及對映 --> <!-- user結果集封裝,可以通過繼承重複使用 --> <resultMap id="userMap" type="user"> <id column="uid" property="uid" /> <result column="name" property="name"/> <result column="password" property="password"/> </resultMap> <!-- loginInfo結果集,繼承user結果集完整資料 --> <resultMap id="userLoginInfoMap" extends="userMap" type="user"> <!-- 使用collection對映多的一方,ofType指定集合中的資料型別 --> <collection property="loginInfos" ofType="loginInfo"> <id column="lid" property="lid"/> <result column="ip" property="ip"/> <result column="loginTime" property="loginTime"/> </collection> </resultMap> <!-- 定義查詢語句 --> <select id="findAllUsers" resultMap="userLoginInfoMap"> select * from users u left join login_infos li on u.uid = li.uid; </select>
2多對一關聯查詢(別名對映|resultMap對映|resultMap結合association對映)
<!-- 2.多對一,採用別名對映關聯關係 --> <select id="findAllLoginInfos" resultType="loginInfo"> select li.*, u.uid "user.uid", u.name "user.name", u.password "user.password" from login_infos li,users u where li.uid = u.uid; </select> <!-- 3.多對一,採用resultMap進行結關聯關係的對映 --> <resultMap id="userMap" type="loginInfo"> <id column="uid" property="user.uid"/> <result column="name" property="user.name"/> <result column="password" property="user.password"/> </resultMap> <!-- 這裡的resultMap繼承關係最好和POJO中的關聯關係保持一致,便於理解 這裡不一致,但也可以執行 --> <resultMap id="userLoginInfoMap" extends="userMap" type="loginInfo"> <id column="lid" property="lid"/> <result column="ip" property="ip"/> <result column="loginTime" property="loginTime"/> </resultMap> <select id="findAllLoginInfos1" resultMap="userLoginInfoMap"> select * from users u,login_infos li where u.uid=li.uid; </select> <!-- 4.多對一,使用resultMap結合association進行關聯關係的對映 --> <resultMap id="loginInfoMap" type="loginInfo"> <id column="lid" property="lid"/> <result column="ip" property="ip"/> <result column="loginTime" property="loginTime"/> </resultMap> <!-- 這裡的resultMap繼承關係和POJO的關聯關係保持了一致,即LoginInfo下有User屬性 --> <resultMap id="loginInfoUserMap" extends="loginInfoMap" type="loginInfo"> <association property="user" javaType="user"> <id column="uid" property="uid"/> <result column="name" property="name"/> <result column="password" property="password"/> </association> </resultMap> <select id="findAllLoginInfos2" resultMap="loginInfoUserMap"> select * from users u,login_infos li where u.uid=li.uid; </select>
2.3多對多關聯查詢
<!-- 13.使用多表查詢,完成多對多查詢,查詢所有的使用者及其角色 --> <!-- 注意:為了避免冗餘,這裡繼承了2.2中的resultMap --> <resultMap id="userRoleMap" extends="userMap" type="user"> <collection property="roles" ofType="role"> <id column="rid" property="rid"/> <result column="name" property="name"/> <result column="description" property="description"/> </collection> </resultMap> <!-- 多對多主要在sql編寫上,需要藉助中間表 --> <select id="findAllUsers" resultMap="userRoleMap"> select * from users u left join users_roles ur on u.uid=ur.uid inner join roles r on ur.rid=r.rid; </select>
五:巢狀查詢和延遲載入
1.載入策略
在關聯查詢時,對於關聯的一方是否查詢出來,要根據業務需求而定。不能通過編碼方式進行策略的改變,而應該通過修改配置檔案改變載入策略。可以使用巢狀查詢(分步查詢)。
2.巢狀查詢
2.1根據多的一方,巢狀查詢少的一方
<!-- 1.巢狀查詢,使用reultMap結合association使用引用的mapper.xml進行查詢 --> <resultMap id="loginInfoMap" type="loginInfo"> <id column="lid" property="lid"/> <result column="ip" property="ip"/> <result column="loginTime" property="loginTime"/> </resultMap> <resultMap id="loginInfoUserMap" extends="loginInfoMap" type="loginInfo"> <!-- 解決user屬性: property:屬性 column:查詢依據,也是當前查詢表的外來鍵 select:指向根據外來鍵查詢的xml唯一對映 --> <association property="user" column="uid" select="cn.dintalk.UserMapper.findById"/> </resultMap> <select id="findAllLoginInfos3" resultMap="loginInfoUserMap"> select * from login_infos; </select> <!-- 在association中,select指向的是另一個Mapper.xml檔案中的對映(根據名稱空間和id) --> <!-- UserMapper.xml中14.巢狀查詢之 根據uid查詢使用者 --> <select id="findById" resultType="user"> select * from users where uid = #{uid}; </select>
2.2根據少的一方,巢狀查詢多的一方
<!-- 2.使用巢狀查詢,可通過懶載入優化sql,查詢所有的使用者及其日誌資訊 --> <!-- 為了簡便,這裡繼承了上述的id為userMap的resultMap --> <resultMap id="userLoginInfoMap" extends="userMap" type="user"> <collection property="loginInfos"column="uid" select="cn.dintalk.dao.LoginInfoMapper.findAllLoginInfos"/> </resultMap> <select id="findAllUser" resultMap="userLoginInfoMap1"> select * from users; </select> <!-- 同理,在collection中,select指向的是另一個Mapper.xml檔案的對映 --> <!--LoginInfoMapper.xml中5.根據使用者id查詢所有的登入資訊 --> <select id="findAllLoginInfos" resultType="loginInfo"> select * from login_infos where uid=#{uid}; </select>
3.配置延遲載入
3.1全域性配置,修改mybatis.xml主配置檔案
<!-- 2.配置延遲載入,即sql優化 --> <settings> <!-- 啟用懶載入策略 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 覆蓋掉延遲載入的觸發方法 --> <setting name="lazyLoadTriggerMethods" value=""/> </settings>
啟用延遲載入後,mybatis預設有toString、equals等4個觸發載入的方法。我們也可以將其覆蓋掉。
延遲載入,即用到關聯資料的時候再去查,不用就不查。(service層中會有很多方法呼叫dao方法,根據service層中的實際需求動態調整載入策略,高效利用資源!)
3.2每個association和collection都有fetchType屬性
該屬性的值會覆蓋掉全域性配置
fetchType="lazy"(預設) | eager
-
lazy : 支援延遲載入
-
eager : 立即載入
六:事務控制及資料來源
1.事務控制
預設情況下:MySql的事務是自動提交的。
通過 JDBC 可以手動控制:
Connection.setAutoCommit(false); Connection.commit(); Connection.rollback();// 開啟事務後,未提交會自動回滾!
MyBatis中: mybatis-config.xml 作如下配置
<transactionManager type="JDBC"></transactionManager>
相當於使用 JDBC 進行事務控制:(增刪改時不提交會自動回滾!)
獲取SqlSession時:SqlSessionFactory.openSession(); // 手動控制事務 ★
SqlSessionFactory.openSession(true); //自動提交事務
2.資料來源
2.1mybatis內建資料來源
mybatis內建了三種資料來源:
UNPOOLED :不帶有池(連線池)|學習時用
POOLED : 帶有池的 | 實際生產環境使用
JNDI : mybatis提供的JndiDataSourceFactory來獲取資料來源
2.2內部原理
POOLED對應的是PooledDataSource資料來源,PooledDataSourceFactory用來生產帶有池的資料來源。
UNPOOLED對應的是UnpooledDataSource資料來源,UnpooledDataSourceFactory用來生產不帶有池的資料來源。
2.3使用Druid等第三方資料來源(以Druid為例)
第一步:引入Druid的Jar包或資料來源
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.14</version> </dependency>
第二步:編寫工廠類,用來產生Druid的資料來源,一般選擇繼承UnpooledDataSourceFactory
public class DataSourceFactory extends UnpooledDataSourceFactory{ public DataSourceFactory(){ this.dataSource = new DruidDataSource();//建立druid資料來源 } }
第三步:在mybatis-config.xml中進行配置
<!--1.類別名的配置 --> <typeAliases> <typeAlias type="cn.dintalk.dataSource.DataSourceFactory" alias="DRUID"/> </typeAliases> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"></transactionManager> <!-- 2.配置druid資料來源 --> <dataSourcetype="DRUID"> <!-- 3.配置資料庫連線:name由資料來源中的setXXX而定,value是外部配置的key --> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments>
七:MyBatis的快取
1.系統快取
MyBatis對快取提供支援,但是在沒有配置的預設情況下,它只開啟一級快取。
1.1一級快取
一級快取只是相對於同一個SqlSession而言的。使用SqlSession第一次查詢後,MyBatis會將其放在快取中,以後再查詢時,如果沒有宣告需要重新整理,且快取未超時的情況下,SqlSession都只會取出當前快取的資料,而不會再次傳送Sql到資料庫。
1.2二級快取
二級快取是在SqlSessionFactory層面上的,可以將快取提供給各個SqlSession物件共享。
開啟二級快取配置
mybatis-confi.xml檔案中(預設開啟,可忽略)
<settings> <!-- 二級快取配置(預設開啟,此行可省略) --> <setting name="cacheEnabled" value="true"/> </settings>
Mapper.xml檔案中
<mapper namespace="cn.dintalk.dao.UserMapper"> <cache/><!-- 開啟二級快取,使用預設配置 --> </mapper> <!-- 使用預設配置意味著: 對映語句檔案中的所有select語句將會被快取。 對映語句檔案中的所有insert、update和delete語句會重新整理快取。 快取使用預設的Least Recently Used(LRU,最近最少使用的)回收策略。 快取會存1024個列表集合或物件(無論查詢方法返回什麼) 快取會被視為是read/write(可讀可寫)的快取 -->
Tips:
-
一級快取中存放的是物件本身,是同一個物件!
-
二級快取中存放的是物件的拷貝,物件所屬類必須實現jav.io.Serializable介面!
配置快取
<cacheevicition="LRU" flushInterval="100000" size="1024" readOnly=true/>
-
eviction: 代表的是快取回收策略,目前MyBatis提供以下策略:
(1)LRU, 最近最少使用的,移除最長時間不用的物件。
(2)FIFO, 先進先出,按物件進入快取的順序來移除它們。
(3)SOFT,軟引用,移除基於垃圾回收器狀態和軟引用規則的物件。
(4)WEAK,弱引用,更積極地移除基於垃圾收集器狀態和弱引用規則的物件。
-
flushInterval: 重新整理間隔時間,單位為毫秒。
-
size: 引用數目,代表快取最多可以儲存多少個物件。
-
readOnly: 只讀,意味著快取資料只讀。
2.自定義快取
系統快取是MyBatis應用機器上的本地快取,我們也可以使用快取伺服器來定製快取,如比較流行的Redis快取。我們需要實現MyBatis為我們提供的介面org.apache.ibatis.cache.Cache,快取介面簡介:
//獲取快取編號 String getId(); //儲存key值快取物件 void putObject(Object key,Object value); //通過key獲取快取物件 Object getObject(Object key); //通過key刪除快取物件 Object removeObject(Object key); //清空快取 void clear(); //獲取快取物件大小 int getSize(); //獲取快取的讀寫鎖 ReadWriterLock getReadWriterLock();
由於每種快取都有其不同的特點,上面的介面都需要我們去實現。假設我們已經有一個實現類:cn.dintalk.MyCache。則配置如下:
<cache type="cn.dintalk.MyCache"/>
完成上述配置,就能使用自定義的快取了。MyBatis也支援在快取中定義常用的屬性,如:
<cache type="cn.dintalk.MyCache"> <property name="host" value="localhost"/> </cache>
如果我們在MyCache這個類中增加setHost(String host) 方法,那麼它在初始化的時候就會被呼叫,這樣我們可以對自定義的快取設定一些外部引數。
Tips:我們也可配置Sql層面的快取規則,來決定它們是否需要重新整理或使用快取。
<insert ...flushCache="true"/> <delete ...flushCache="true"/> <update ...flushCache="true"/> <select ...flushCache="false" useCache="true"/>
八:附錄-MyBatis常用配置及開發Tips
附錄1:mybatis-config.xml常用配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 1.引入外部的配置檔案 --> <properties resource="jdbc.properties"/> <!-- 2.配置延遲載入,即sql優化 --> <settings> <!-- 啟用懶載入策略 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 覆蓋掉延遲載入的觸發方法 --> <setting name="lazyLoadTriggerMethods" value=""/> <!-- 二級快取配置(預設開啟,此行可省略) --> <!-- 使用二級快取,在對應的mapper.xml中加入cache即可 --> <!--<setting name="cacheEnabled" value="true"/>--> </settings> <!-- 3.類別名的配置 --> <typeAliases> <!-- 單個類的配置 --> <!--<typeAlias type="cn.dintalk.domain.User" alias="user"/>--> <!-- 配置druid資料來源工廠類別名 --> <typeAlias type="cn.dintalk.dataSource.DataSourceFactory" alias="DRUID"/> <!-- 給包中所有的類配置預設別名, 即類名首字母小寫--> <package name="cn.dintalk.domain"/> </typeAliases> <!-- 4.使用預設的環境配置(可以是多個) --> <environments default="mysql"> <environment id="mysql"> <!-- 事務管理器,此處配置 為JDBC --> <transactionManager type="JDBC"></transactionManager> <!-- 資料來源配置,此處配置為 POOLED--> <!--<dataSourcetype="POOLED">--> <!-- 配置druid資料來源 --> <dataSourcetype="DRUID"> <!-- 配置資料庫連線:name由資料來源中的setXXX而定,value是外部配置的key --> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments> <!-- 5.註冊對映檔案 --> <mappers> <!-- 指定資原始檔路徑 --> <!--<mapper resource="cn/dintalk/dao/UserMapper.xml"></mapper>--> <!--<mapper resource="cn/dintalk/dao/LoginInfoMapper.xml"></mapper>--> <!-- 基於Mapper介面的開發:指定類名--> <!--<mapper class="cn.dintalk.dao.UserMapper"/>--> <!-- 指定基於Mapper介面開發的包:(需類名和xml檔名一致,包名一致)--> <package name="cn.dintalk.dao"/> </mappers> </configuration>
附錄2:Mapper.xml頭約束
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.dintalk.dao.UserMapper"> <cache/> <!-- 開啟二級快取 --> </mapper>