上一篇介紹了JDBC的相關概念、MyBatis的特性與Hibernate的區別、MyBatis的基本元件與生命週期,基本可以使用MyBatis了。
文章索引:
這一篇詳細介紹MyBatis的配置,首先看下配置XML檔案的層次結構,然後詳細介紹每個配置項,說明每項的作用,值的取值與含義。
下面列出MyBatis配置XML檔案的層次結構,這些層次是不能夠顛倒順序的。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<properties/>
<settings/>
<typeAliases/>
<typeHandles/>
<objectFactory/>
<plugins/>
<environments>
<environment>
<transanctionManager/> <!-- 配置事務管理器 -->
<dataSource/> <!-- 配置資料來源 -->
</environment>
</environments>
<databaseIdProvider/> <!-- 資料庫廠商標識 -->
<mappers/> <!-- 對映器 -->
</configuration>
複製程式碼
properties元素
將一些公用、經常變更的值單獨宣告,能在配置檔案的上下文中使用它,MyBatis提供了3種配置方式:
- property子元素
- properties配置檔案
- 程式引數傳遞
property子元素
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mi-user"/>
<property name="username" value="root"/>
<property name="pwd" value="123456"/>
</properties>
複製程式碼
properties配置檔案
建立一個配置檔案 jdbc.properties
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mi-user
username = root
password = 123456
複製程式碼
設定properties配置檔案
<properties resource='jdbc.properties' />
複製程式碼
程式引數傳遞
實際工作中,會遇到這種場景:系統由運維人員配置,生成資料庫的密碼對開發者是保密的,對使用者名稱和密碼進行了加密。可以通過程式引數傳遞的方式,先解密,再設定property。
//讀入配置檔案流
InputStream cfgStream = Resources.getResourceAsStream("mybatis-config.xml");
Reader cfgReader = new InputStreamReader(cfgStream);
//讀入屬性檔案流
InputStream proStream = Resources.getResourceAsStream("jdbc.properties");
Reader proReader = new InputStreamReader(proStream);
Properties properties = new Properties();
properties.load(proReader);
//轉換為明文
properties.setProperty("username",decode(properties.getProperty("username")));
properties.setProperty("pwd",decode(properties.getProperty("pwd")));
//建立sqlSessionFactory
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(cfgReader,properties);
複製程式碼
如果3種配置同時出現,優先順序為第3種 > 第2種 > 第1種,推薦使用第2種,有特殊需求時使用第3種。
設定
設定會改變MyBatis執行時的行為,設定項很多,只會介紹常用的配置,想了解全部配置可以檢視官方文件。
- cacheEnabled,全域性地開啟或關閉配置檔案中的所有對映器已經配置的任何快取,預設為true;
- lazyLoadingEnabled,延遲載入的全域性開關,當開啟時,所有關聯物件都會延遲載入,特定關聯關係中可通過設定fetchType屬性來覆蓋該項的開關狀態,預設為false;
- aggressiveLazyLoading,當開啟時,任何方法的呼叫都會載入該物件的所有屬性。否則,每個屬性會按需載入,3.4.1版本之前預設為true,3.4.1之後預設為false;
- autoMappingBehavior,指定MyBatis應如何自動對映列到欄位或屬性,NONE 表示取消自動對映,PARTIAL 只會自動對映沒有定義巢狀結果集對映的結果集,FULL 會自動對映任意複雜的結果集,預設為PARTIAL;
- autoMappingUnknownColumnBehavior,指定發現自動對映目標未知列(或者未知屬性型別)的行為,NONE: 不做任何反應,WARNING: 輸出提醒日誌,FAILING: 對映失敗,預設為NONE;
- defaultStatementTimeout,設定超時時間,它決定驅動等待資料庫響應的秒數;
- mapUnderscoreToCamelCase,是否開啟自動駝峰命名規則(camel case)對映,即從經典資料庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的類似對映,預設為false;
- defaultEnumTypeHandler,指定 Enum 使用的預設 TypeHandler,預設為org.apache.ibatis.type.EnumTypeHandler;
- returnInstanceForEmptyRow,當返回行的所有列都是空時,MyBatis預設返回null。 當開啟這個設定時,MyBatis會返回一個空例項,預設為false;
- localCacheScope,MyBatis 利用本地快取機制(Local Cache)防止迴圈引用(circular references)和加速重複巢狀查詢。 預設值為 SESSION,這種情況下會快取一個會話中執行的所有查詢。 若設定值為 STATEMENT,本地會話僅用在語句執行上,對相同 SqlSession 的不同呼叫將不會共享資料,預設為SESSION;
- logImpl,指定日誌的具體實現,比如SLF4J|LOG4J|COMMONS_LOGGING等;
別名
在配置對映檔案中,需要指定類的全限定名,為了簡化,可以宣告一個簡短的名稱去指代它,可以在MyBatis上下文中使用。系統已經為我們定義了常用的型別,比如數值、字串、日期、集合等。對於自定義的業務POJO,需要自定義別名。
<typeAliases>
<typeAlias alias="role" type="com.learn.chapter2.po.Role"/>
</typeAliases>
複製程式碼
也可以通過註解方式進行,首先配置一個掃描的包,然後在類定義時新增註解@Alias("role")。
<typeAliases>
<package name="com.learn.chapter2.po" />
</typeAliases>
複製程式碼
@Alias("role")
public class Role{
}
複製程式碼
型別處理器
MyBatis在預處理語句中設定一個引數時,或者從結果集中取出一個值時,都會用註冊了的typeHader進行處理。typeHander的作用就是將引數從javaType轉化為jdbcType,或者從資料庫取出結果時把jdbcType轉化為javaType。
系統內部已經定義了常用的型別處理器,有些情況下,需要自定義。
MyBatis也提供了列舉型別的型別處理器,有2個轉化列舉型別的typeHandler,EnumTypeHandler和EnumOrdinalTypeHandler,其中EnumTypeHandler是使用列舉字串名稱作為引數傳遞的,EnumOrdinalTypeHandler是使用整數下標作為引數傳遞的。
但這2個列舉型別應用不那麼廣泛,更多的時候,需要自定義typeHandler進行處理。
自定義型別處理器,首先要定義型別處理類,實現TypeHandler泛型介面:
public class SexEnumTypeHandler implements TypeHandler<Sex> {
@Override
public void setParameter(PreparedStatement ps, int i, Sex sex, JdbcType jdbcType) throws SQLException {
ps.setInt(i, sex.getId());
}
@Override
public Sex getResult(ResultSet rs, String name) throws SQLException {
return Sex.getSex(rs.getInt(name));
}
@Override
public Sex getResult(ResultSet rs, int id) throws SQLException {
return Sex.getSex(id);
}
@Override
public Sex getResult(CallableStatement cs, int id) throws SQLException {
return Sex.getSex(cs.getInt(id));
}
}
複製程式碼
然後註冊自定義的TypeHandler
<typeHandlers>
<typeHandler handler="com.qqdong.study.SexEnumTypeHandler" javaType="sex"/>
</typeHandlers>
複製程式碼
最後,在定義對映器時,指定typeHandler即可
<select id="getUser" parameterType="long" resultType="userMap">
</select>
<resultMap id="userMap" type="user">
<result column="sex" property="sex" typeHandler="com.qqdong.study.SexEnumTypeHandler">
</resultMap>
複製程式碼
ObjectFactory
當MyBatis在構建一個結果返回的時候,都會使用ObjectFactory去構建POJO,在MyBatis中可以定製自己的物件工廠。一般不用配置,使用預設的DefaultObjectFactory即可。
外掛plugin
外掛比較複雜,後續單獨一篇文章介紹。
environments配置環境
配置環境可以註冊多個資料來源,每個資料來源包括基本配置和資料庫事務配置。
<environments default="development">
<environment id="development">
<!-- 採用jdbc事務管理 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="false">
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
複製程式碼
其中,transactionManager指定資料庫事務,有3種配置方法:
- JDBC,採用JDBC方式管理事務,在獨立編碼中常常使用;
- MANAGED,採用容器方式管理事務,在JNDI資料來源中常用;
- 自定義,由使用者自定義資料庫事務管理方法;
dataSource標籤,配置資料來源連線資訊,type配置對資料庫連線方式,有以下幾種:
- UNPOOLED:非連線池資料庫;
- POOLED:連線池資料庫;
- JNDI:JNDI資料來源;
- 自定義資料來源;
databaseIdProvider資料庫廠商標識
該屬性的作用在於指定SQL到對應的資料庫廠商提供的資料庫中執行。不常用,就不介紹了。
對映器
對映器是MyBatis最複雜、最核心的配置,包括引數型別、動態SQL、定義SQL、快取資訊等功能,上篇文章也演示了具體的例子,下篇文章會重點介紹細節。
歡迎掃描下方二維碼,關注我的個人微信公眾號 ~