mybatis-configuration.xml是MyBatis的全局配置文件(文件名任意),其配置內容和順序如下:
properties : 屬性(文件)加載/配置 settings : 全局配置參數 typeAliases : 定義類型別名 typeHandlers : 類型處理器 objectFactory : 對象工廠 plugins : 插件 environments : 環境集合屬性對象方便對配置參數統一管理,供其他XML引用,我們可以將數據庫的連接參數抽取出來:
db.properties
## Data Source
mysql.driver.class=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://host:port/db?characterEncoding=utf-8
mysql.user=user
mysql.password=password
mybatis-configuration.xml
<code class=" hljs avrasm"><code class=" hljs xml"><properties resource="db.properties"> <environments default="development"> <environment id="development"> <!--{cke_protected}{C}%3C!%2D%2D%20%E9%85%8D%E7%BD%AEJDBC%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%2D%2D%3E--> <transactionmanager type="JDBC"> <!--{cke_protected}{C}%3C!%2D%2D%20%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E6%BA%90%2D%2D%3E--> <datasource type="POOLED"> <property name="driver" value="${mysql.driver.class}"> <property name="url" value="${mysql.url}"> <property name="username" value="${mysql.user}"> <property name="password" value="${mysql.password}"> </property></property></property></property></datasource> </transactionmanager></environment> </environments></properties></code></code>
注: MyBatis按照如下順序加載properties:
1) 在標簽內定義的屬性;
2) .properties文件中定義的屬性;
3) 最後讀取作為方法參數傳遞的屬性.
settings
MyBatis全局配置參數,會影響MyBatis運行時行為(如:開啟二級緩存/延遲加載).見MyBatis文檔.
typeAliases
MyBatis默認支持的類型別名可參考MyBatis文檔,我們也可以自定義別名,但並不推薦,使用PO對象的全限定名可以提高Statement的可讀性.
typeHandlers
typeHandlers用於Java類型和JDBC類型轉換,MyBatis提供了很多默認的類型處理器(詳見MyBatis文檔),而且也基本滿足日常開發需求,因此一般就不再需要單獨定義.
mappers
前面已經將SQL語句定義到了mapper文件中,那麼
配置
描述
使用類路徑的資源(Resources/java目錄下)
使用完全限定路徑
使用mapper接口類路徑
注冊指定包下的所有mapper接口
注意:後兩種方式要求mapper接口名和mapper映射文件名稱相同,且放在同一個目錄中(不推薦).
其他關於MyBatis的配置信息可參考MyBatis文檔.
整合Spring
實現MyBatis與Spring整合之後,可以使用Spring來管理SqlSessionFactory和mapper接口,Spring自動使用SqlSessionFactory創建SqlSession,並將實現好DAO接口注冊到Spring容器中, 供@Autowired使用.
1. 添加依賴
添加Spring支持
org.springframework
spring-core
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-beans
${spring.version}
org.springframework
spring-expression
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-test
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-tx
${spring.version}
添加MyBatis-Spring包
org.mybatis
mybatis-spring
${mybatis-spring.version}
添加Hikaricp數據庫連接池
com.zaxxer
HikariCP
${hikaricp.version}
不要忘了MySQL數據庫驅動
mysql
mysql-connector-java
${mysql.version}
2. 配置文件
精簡mybatis-configuration.xml
可以將數據源的配置移到下面的applicationContext-datasource.xml中.
<code class=" hljs avrasm"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20%3F%2D%2D%3E--> <configuration> <mappers> <mapper resource="mybatis/mapper/UserDAO.xml"> </mapper></mappers> </configuration></code></code></code></code></code></code></code>
定義applicationContext-datasource.xml
<code class=" hljs avrasm"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:db.properties"> <!--{cke_protected}{C}%3C!%2D%2D%20%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E6%BA%90%20%2D%2D%3E--> <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig"> <property name="driverClassName" value="${mysql.driver.class}"> <property name="jdbcUrl" value="${mysql.url}"> <property name="username" value="${mysql.user}"> <property name="password" value="${mysql.password}"> <property name="maximumPoolSize" value="5"> <property name="maxLifetime" value="700000"> <property name="idleTimeout" value="600000"> <property name="connectionTimeout" value="10000"> <property name="dataSourceProperties"> <props> <prop key="dataSourceClassName">com.mysql.jdbc.jdbc2.optional.MysqlDataSource</prop> <prop key="cachePrepStmts">true</prop> <prop key="prepStmtCacheSize">250</prop> <prop key="prepStmtCacheSqlLimit">2048</prop> </props> </property> </property></property></property></property></property></property></property></property></bean> <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"> <constructor-arg ref="hikariConfig"> </constructor-arg></bean> <!--{cke_protected}{C}%3C!%2D%2D%20%E9%85%8D%E7%BD%AESqlSessionFactory%20%2D%2D%3E--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"> <property name="configLocation" value="classpath:mybatis/mybatis-configuration.xml"> </property></property></bean> <!--{cke_protected}{C}%3C!%2D%2D%20%E6%A0%B9%E6%8D%AEmapper%E6%8E%A5%E5%8F%A3%E7%94%9F%E6%88%90%E4%BB%A3%E7%90%86%E5%AF%B9%E8%B1%A1%20%2D%2D%3E--> <bean id="dao" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.fq.mybatis.UserDAO"> <property name="sqlSessionFactory" ref="sqlSessionFactory"> </property></property></bean> </context:property-placeholder></beans></code></code></code></code></code></code></code></code>
上面的配置存在一個問題:需要針對每個mapper配置一個MapperFactoryBean(繁瑣),因此這段根據mapper接口生成代理對象的配置可更改如下:
<code class=" hljs avrasm"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%20%E5%9F%BA%E4%BA%8E%E5%8C%85%E6%89%AB%E6%8F%8F%E7%9A%84mapper%E9%85%8D%E7%BD%AE%20%2D%2D%3E--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.fq.mybatis"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"> </property></property></bean></code></code></code></code></code></code></code></code></code>
附: applicationContext-database.xml完整配置可參考: Git地址
定義Spring主配置文件applicationContext.xml
定義注解驅動及加載靜態配置文件datasource:
<code class=" hljs avrasm"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%2D%2D%3E--> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--{cke_protected}{C}%3C!%2D%2D%20%E6%B3%A8%E8%A7%A3%E9%A9%B1%E5%8A%A8%20%2D%2D%3E--> <context:annotation-config> <!--{cke_protected}{C}%3C!%2D%2D%20%E5%8A%A0%E8%BD%BD%E9%9D%99%E6%80%81%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%20%2D%2D%3E--> <import resource="applicationContext-datasource.xml"> </import></context:annotation-config></beans></code></code></code></code></code></code></code></code></code></code>
Client
/**
* @author jifang
* @since 16/2/22 上午10:20.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
public class UserDAOClient {
@Autowired
private UserDAO dao;
@Test
public void client() throws Exception {
User user = dao.selectUserById(1);
System.out.println(user);
}
}
緩存
<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxjb2RlIGNsYXNzPQ=="hljs avrasm">與大多數持久層框架一樣,MyBatis也支持一級緩存和二級緩存.
緩存作用是提升系統整體性能(不是提升數據庫性能:因為緩存將數據庫中的數據存放到內存,下次查詢同樣內容時直接從內存讀取,減輕數據庫壓力,而且直接從內存中讀取數據要比從數據庫檢索快很多,因此可以提升系統整體性能).
緩存數據更新:當一個作用域(一級緩存為SqlSession/二級緩存為namespace)進行了C/U/D操作後,默認該作用域下所有緩存都被清空.
一級緩存
MyBatis默認開啟了一級緩存.一級緩存是基於org.apache.ibatis.cache.impl.PerpetualCache的HashMap本地緩存,其存儲作用域為SqlSession,同一個SqlSession幾次執行相同SQL,後面的查詢會直接從緩存中加載,從而提高查詢效率/減輕數據庫壓力.當SqlSession經flush/close後,該SqlSession中的所有Cache數據被清空.
二級緩存
與一級緩存機制類似,MyBatis二級緩存默認也是采用PerpetualCache的HashMap存儲,不同在於二級緩存存儲作用域為namespace/mapper,並且可以自定義緩存實現,如Ehcache.
MyBatis默認沒有開啟二級緩存,需要經過以下步驟才能使用:
啟用二級緩存(可選)
其需要在mybatis-configuration.xml的settings全局參數中開啟:
<code class=" hljs avrasm"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs java"><code class=" hljs xml"><settings> <setting name="cacheEnabled" value="true"> </setting></settings></code></code></code></code></code></code></code></code></code></code></code></code>
cacheEnabled對此配置文件下的所有cache進行全局性開/關設置(默認為true).
配置緩存策略
在mapper映射文件中添加標簽,以指定該namespace開啟二級緩存, 並指定緩存策略:
1) eviction:緩存淘汰算法:
算法
描述
釋義
LRU
最近最少使用
移除最長時間不被使用的對象(默認).
FIFO
先進先出
按對象進入緩存的順序移除.
SOFT
軟引用
移除基於垃圾回收器狀態和軟引用規則的對象.
WEAK
弱引用
更積極地移除基於垃圾收集器狀態和弱引用規則的對象.
2) flushInterval:刷新間隔(緩存過期時間),單位為毫秒,MyBatis會每隔一段時間自動清空緩存(默認刷新間隔為空, 即永不過期,僅調用語句時刷新).
3) size:引用數目,要記住你緩存的對象的數目和運行環境可用內存資源數目(默認1024).
4) readOnly: 只讀.如果為true,則所有相同SQL返回同一對象(因此這些對象不能修改,有助於提高性能,但並發操作同一條數據時,可能不安全);如果為false,則相同SQL後面返回的是cache的clone副本(通過序列化,慢一些但更是安全,因此默認是false).
序列化
PO對象要實現Serializable序列化,因為二級緩存的存儲介質不一定只是內存:
public class User implements Serializable {
//...
}
Client
@Test
public void cacheClient() throws Exception {
testCache(factory.openSession());
testCache(factory.openSession());
testCache(factory.openSession());
}
private void testCache(SqlSession session) throws Exception {
UserDAO dao = session.getMapper(UserDAO.class);
dao.selectUserById(1);
// 需要將SqlSession關閉才能將數據寫入緩存.
session.close();
}
運行代碼, 並觀察log輸出的命中率(Cache Hit Ratio).
Statement配置
1) 禁用緩存: 在Statement中設置useCache="false"可以禁用當前select語句的二級緩存(默認為true:該SQL啟用二級緩存).
<code class=" hljs bash"><code class=" hljs java"><code class=" hljs java"><code class=" hljs vbnet"><select id="selectUserById" parametertype="java.lang.Integer" resulttype="com.fq.domain.User" usecache="true">
SELECT *
FROM user
WHERE id = #{id};
</select></code></code></code></code>
2)刷新緩存: 同一個namespace中,如果還有其它insert/update/delete操作,需要刷新緩存,使用flushCache="true"屬性設置(默認為true刷新緩存).
<code class=" hljs bash"><code class=" hljs java"><code class=" hljs java"><code class=" hljs vbnet"><code class=" hljs xml"><insert id="insertUserList" parametertype="java.util.List" flushcache="true">
INSERT INTO user(name, password) VALUES
<if test="list != null and list.size != 0">
<foreach collection="list" item="user" separator=",">
(#{user.name}, #{user.password})
</foreach>
</if>
</insert></code></code></code></code></code>
整合Ehcache
MyBatis暴露一個org.apache.ibatis.cache.Cache接口出來,通過實現該接口,可以實現各類緩存產品(如Ehcache/Redis/Memcached)與MyBatis的整合(MyBatis的特長操作數據庫,緩存管理並不是其擅長,因此整合其他緩存產品可以提高系統整體性能).
Ehcache是一個純Java開發的進程內緩存框架,具有開源/快速/靈活等特點,是Hibernate默認的CacheProvider.使用Ehcache需要在pom.xml中添加如下依賴:
<code class=" hljs bash"><code class=" hljs java"><code class=" hljs java"><code class=" hljs vbnet"><code class=" hljs xml"><code class=" hljs xml"><dependency>
<groupid>net.sf.ehcache</groupid>
<artifactid>ehcache-core</artifactid>
<version>2.6.11</version>
</dependency>
<dependency>
<groupid>org.mybatis.caches</groupid>
<artifactid>mybatis-ehcache</artifactid>
<version>1.0.3</version>
</dependency></code></code></code></code></code></code>
配置Ehcache
在Resources目錄下添加ehcache.xml配置文件
<code class=" hljs bash"><code class=" hljs java"><code class=" hljs java"><code class=" hljs vbnet"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><ehcache>
<diskstore path="/data/cache">
<defaultcache maxelementsinmemory="1000" maxelementsondisk="10000000" eternal="false" overflowtodisk="false" timetoidleseconds="120" timetoliveseconds="120" diskexpirythreadintervalseconds="120" memorystoreevictionpolicy="LRU">
</defaultcache>
</diskstore></ehcache></code></code></code></code></code></code></code>
屬性
描述
diskStore
指定緩存數據在磁盤的存儲位置
maxElementsInMemory
在內存中緩存element的最大數目
maxElementsOnDisk
在磁盤上緩存element的最大數目,0表示無窮大
eternal
設定緩存的elements是否永遠不過期.true,則緩存的數據始終有效,如果為false那麼還要根據timeToIdleSeconds,timeToLiveSeconds判斷
overflowToDisk
設定當內存緩存溢出的時候是否將過期的element緩存到磁盤上
timeToIdleSeconds
刷新間隔:緩存數據前後兩次訪問時間超過timeToIdleSeconds時,這些數據便會刪除(默認為0,時間間隔無窮大)
timeToLiveSeconds
緩存element的有效生命期(默認為0,時間無限)
diskSpoolBufferSizeMB
設置DiskStore(磁盤緩存)緩存區大小.默認是30MB.
diskPersistent
在JVM重啟時是否使用磁盤保存Ehcache數據,默認是false.
diskExpiryThreadIntervalSeconds
磁盤緩存的清理線程運行間隔,默認是120秒.
memoryStoreEvictionPolicy
當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略.默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出)
mapper配置ehcache
還可以根據需求調整當前namespace的緩存參數:
<code class=" hljs java"><code class=" hljs bash"><code class=" hljs java"><code class=" hljs java"><code class=" hljs vbnet"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs xml"><code class=" hljs bash"><code class=" hljs xml"><cache type="org.mybatis.caches.ehcache.EhcacheCache">
<property name="timeToIdleSeconds" value="3600">
<property name="timeToLiveSeconds" value="3600">
<!--{cke_protected}{C}%3C!%2D%2D%20%E5%90%8Cehcache%E5%8F%82%E6%95%B0maxElementsInMemory%20%2D%2D%3E-->
<property name="maxEntriesLocalHeap" value="1000">
<!--{cke_protected}{C}%3C!%2D%2D%20%E5%90%8Cehcache%E5%8F%82%E6%95%B0maxElementsOnDisk%20%2D%2D%3E-->
<property name="maxEntriesLocalDisk" value="10000000">
<property name="memoryStoreEvictionPolicy" value="LRU">
</property></property></property></property></property></cache></code></code></code></code></code></code></code></code></code></code>
適用場景
對於查詢請求多且對查詢結果實時性要求不高的場景,可采用二級緩存降低數據庫負擔,提高訪問速度(業務場景如:微博/動態/訂單信息等). 局限
二級緩存對細粒度級別的緩存實現不好,如”緩存所有的商品信息時,二級緩存就無法實現當一個商品信息變化時只刷新該商品緩存而不刷新全部商品緩存“,因為二級緩存區域以namespace為單位劃分,當一個商品發生變化會將所有商品緩存清空,因此解決此類問題需要在上層對數據進行業務劃分.
二級緩存小結