標簽: Java與存儲
Configuration
mybatis-configuration.xml是MyBatis的全局配置文件(文件名稱隨意),其配置內容和順序例如以下:
- properties : 屬性(文件)載入/配置
- settings : 全局配置參數
- typeAliases : 定義類型別名
- typeHandlers : 類型處理器
- objectFactory : 對象工廠
- plugins : 插件
- environments : 環境集合屬性對象
- environment
- transactionManager : 事務管理
- dataSource : 數據源
- environment
- databaseIdProvider:P數據庫廠商標識
- mappers : 映射器
properties
方便對配置參數統一管理,供其它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
<properties resource="db.properties"/><environments default="development"><environment id="development"><!-- 配置JDBC事務管理--><transactionManager type="JDBC"/><!-- 配置數據源--><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}"/></dataSource></environment>
</environments>
注: MyBatis依照例如以下順序載入properties:
1) 在<properties>
標簽內定義的屬性;
2) .properties文件里定義的屬性;
3) 最后讀取作為方法參數傳遞的屬性.
settings
MyBatis全局配置參數,會影響MyBatis執行時行為(如:開啟二級緩存/延遲載入).見MyBatis文檔.
typeAliases
MyBatis默認支持的類型別名可參考MyBatis文檔,我們也能夠自己定義別名,但并不推薦,使用PO對象的全限定名能夠提高Statement的可讀性.
typeHandlers
typeHandlers
用于Java類型和JDBC類型轉換,MyBatis提供了非常多默認的類型處理器(詳見MyBatis文檔),并且也基本滿足日常開發需求,因此一般就不再須要單獨定義.
mappers
前面已經將SQL語句定義到了mapper文件里,那么<mappers/>
屬性就是告訴MyBatis到哪里去尋找mapper文件,MyBatis提供了例如以下幾種配置方法:
配置 | 描寫敘述 |
---|---|
<mapper resource=""/> | 使用類路徑的資源(Resources /java 文件夾下) |
<mapper url=""/> | 使用全然限定路徑 |
<mapper class=""/> | 使用mapper接口類路徑 |
<package name=""/> | 注冊指定包下的全部mapper接口 |
注意:后兩種方式要求mapper接口名和mapper映射文件名稱稱同樣,且放在同一個文件夾中(不推薦).
其它關于MyBatis的配置信息可參考MyBatis文檔.
整合Spring
實現MyBatis與Spring整合之后,能夠使用Spring來管理SqlSessionFactory
和mapper接口,Spring自己主動使用SqlSessionFactory
創建SqlSession
,并將實現好DAO接口注冊到Spring容器中, 供@Autowired
使用.
1. 加入依賴
- 加入Spring支持
<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-expression</artifactId><version>${spring.version}</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version>
</dependency>
- 加入MyBatis-Spring包
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>${mybatis-spring.version}</version>
</dependency>
- 加入Hikaricp數據庫連接池
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>${hikaricp.version}</version>
</dependency>
- 不要忘了MySQL數據庫驅動
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version>
</dependency>
2. 配置文件
- 精簡mybatis-configuration.xml
能夠將數據源的配置移到以下的applicationContext-datasource.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><mappers><mapper resource="mybatis/mapper/UserDAO.xml"/></mappers>
</configuration>
- 定義applicationContext-datasource.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"/><!-- 配置數據源 --><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></bean><bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"><constructor-arg ref="hikariConfig"/></bean><!-- 配置SqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="configLocation" value="classpath:mybatis/mybatis-configuration.xml"/></bean><!-- 依據mapper接口生成代理對象 --><bean id="dao" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="mapperInterface" value="com.fq.mybatis.UserDAO"/><property name="sqlSessionFactory" ref="sqlSessionFactory"/></bean>
</beans>
上面的配置存在一個問題:須要針對每一個mapper配置一個MapperFactoryBean
(繁瑣),因此這段依據mapper接口生成代理對象的配置可更改例如以下:
<!-- 基于包掃描的mapper配置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.fq.mybatis"/><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
附: applicationContext-database.xml完整配置可參考: Git地址
- 定義Spring主配置文件applicationContext.xml
定義注解驅動及載入靜態配置文件datasource:
<?
xml version="1.0" encoding="UTF-8"?>
<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:annotation-config/> <!-- 載入靜態配置文件 --> <import resource="applicationContext-datasource.xml"/> </beans>
- Client
/*** @author jifang* @since 16/2/22 上午10:20.*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
public class UserDAOClient {@Autowiredprivate UserDAO dao;@Testpublic void client() throws Exception {User user = dao.selectUserById(1);System.out.println(user);}
}
緩存
與大多數持久層框架一樣,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
全局參數中開啟:
<settings><setting name="cacheEnabled" value="true"/>
</settings>
cacheEnabled
對此配置文件下的全部cache進行全局性開/關設置(默覺得true
).
- 配置緩存策略
在mapper映射文件里加入<cache/>
標簽,以指定該namespace開啟二級緩存, 并指定緩存策略:
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
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啟用二級緩存).
<select id="selectUserById" parameterType="java.lang.Integer" resultType="com.fq.domain.User" useCache="true">SELECT *FROM userWHERE id = #{id};
</select>
2)刷新緩存: 同一個namespace中,假設還有其它insert/update/delete操作,須要刷新緩存,使用flushCache="true"
屬性設置(默覺得true
刷新緩存).
<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>
整合Ehcache
MyBatis暴露一個org.apache.ibatis.cache.Cache
接口出來,通過實現該接口,能夠實現各類緩存產品(如Ehcache/Redis/Memcached)與MyBatis的整合(MyBatis的特長操作數據庫,緩存管理并非其擅長,因此整合其它緩存產品能夠提高系統總體性能).
Ehcache是一個純Java開發的進程內緩存框架,具有開源/高速/靈活等特點,是Hibernate默認的CacheProvider.使用Ehcache須要在pom.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>
- 配置Ehcache
在Resources文件夾下加入ehcache.xml配置文件
<ehcache><diskStore path="/data/cache"/><defaultCache
maxElementsInMemory="1000"maxElementsOnDisk="10000000"eternal="false"overflowToDisk="false"timeToIdleSeconds="120"timeToLiveSeconds="120"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"></defaultCache>
</ehcache>
屬性 | 描寫敘述 |
---|---|
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
<cache type="org.mybatis.caches.ehcache.EhcacheCache" eviction="LRU" flushInterval="60000" size="1024"readOnly="true"/>
還能夠依據需求調整當前namespace的緩存參數:
<cache type="org.mybatis.caches.ehcache.EhcacheCache"><property name="timeToIdleSeconds" value="3600"/><property name="timeToLiveSeconds" value="3600"/><!-- 同ehcache參數maxElementsInMemory --><property name="maxEntriesLocalHeap" value="1000"/><!-- 同ehcache參數maxElementsOnDisk --><property name="maxEntriesLocalDisk" value="10000000"/><property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
二級緩存小結
- 適用場景
對于查詢請求多且對查詢結果實時性要求不高的場景,可採用二級緩存減少數據庫負擔,提高訪問速度(業務場景如:微博/動態/訂單信息等). - 局限
二級緩存對細粒度級別的緩存實現不好,如”緩存全部的商品信息時,二級緩存就無法實現當一個商品信息變化時僅僅刷新該商品緩存而不刷新全部商品緩存“,由于二級緩存區域以namespace
為單位劃分,當一個商品發生變化會將全部商品緩存清空,因此解決此類問題須要在上層對數據進行業務劃分.