那些你必須知道的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數據源 -->
<dataSource type="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接口!
配置緩存
<cache evicition="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-->
<!--<dataSource type="POOLED">-->
<!-- 配置druid數據源 -->
<dataSource type="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>
那些你必須知道的MyBatis實用知識點