MyBatis xml配置文件詳解

一、MyBatis 配置文件基本結構

       在使用mybatis框架時,首先導入其對應的jar包,並進行相應的配置,所以得對配置文件的每個參數都得了解。一個完全的mybatis配置文件結構如下:

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE configuration  
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">  
  5. <!-- 配置文件的根元素 -->  
  6. <configuration>  
  7.     <!-- 屬性:定義配置外在化 -->  
  8.     <properties></properties>  
  9.     <!-- 設置:定義mybatis的一些全局性設置 -->  
  10.     <settings>  
  11.        <!-- 具體的參數名和參數值 -->  
  12.        <setting name="" value=""/>   
  13.     </settings>  
  14.     <!-- 類型名稱:爲一些類定義別名 -->  
  15.     <typeAliases></typeAliases>  
  16.     <!-- 類型處理器:定義Java類型與數據庫中的數據類型之間的轉換關係 -->  
  17.     <typeHandlers></typeHandlers>  
  18.     <!-- 對象工廠 -->  
  19.     <objectFactory type=""></objectFactory>  
  20.     <!-- 插件:mybatis的插件,插件可以修改mybatis的內部運行規則 -->  
  21.     <plugins>  
  22.        <plugin interceptor=""></plugin>  
  23.     </plugins>  
  24.     <!-- 環境:配置mybatis的環境 -->  
  25.     <environments default="">  
  26.        <!-- 環境變量:可以配置多個環境變量,比如使用多數據源時,就需要配置多個環境變量 -->  
  27.        <environment id="">  
  28.           <!-- 事務管理器 -->  
  29.           <transactionManager type=""></transactionManager>  
  30.           <!-- 數據源 -->  
  31.           <dataSource type=""></dataSource>  
  32.        </environment>   
  33.     </environments>  
  34.     <!-- 數據庫廠商標識 -->  
  35.     <databaseIdProvider type=""></databaseIdProvider>  
  36.     <!-- 映射器:指定映射文件或者映射類 -->  
  37.     <mappers></mappers>  
  38. </configuration>  

properties

properties元素主要是用來定義配置外在化,比如數據庫的連接屬性等。這些屬性都是可外部配置且可動態替換的,既可以在典型的Java屬性文件中配置,亦可以通過properties元素的子元素來傳遞。例如:

[html] view plain copy
  1. <properties resource="org/mybatis/example/config.properties">  
  2.   <property name="username" value="dev_user"/>  
  3.   <property name="password" value="F2Fa3!33TYyg"/>  
  4. </properties>  
其中的屬性就可以在整個配置文件中使用來替換需要動態配置的屬性值。比如在數據源中使用的例子:

[html] view plain copy
  1. <dataSource type="POOLED">  
  2.   <property name="driver" value="${driver}"/>  
  3.   <property name="url" value="${url}"/>  
  4.   <property name="username" value="${username}"/>  
  5.   <property name="password" value="${password}"/>  
  6. </dataSource>  
這個例子中的username和password將會由properties元素中設置的相應值來替換。driver和url屬性將會由config.properties文件中對應的值來替換。這樣就爲配置提供了諸多靈活選擇。屬性也可以被傳遞到SqlSessionBuilder.build()方法中。例如:

[html] view plain copy
  1. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props);  
  2.   
  3.   
  4. // ... or ...  
  5.   
  6.   
  7. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);  
但是,這也就涉及到了優先級的問題,如果屬性不只在一個地方配置,那麼mybatis將會按照下面的順序來加載:

  • 在properties元素體內指定的屬性首先被讀取。
  • 然後根據properties元素中的resource屬性讀取類路徑下屬性文件或根據url屬性指定的路徑讀取屬性文件,並覆蓋已讀取的同名屬性。
  • 最後讀取作爲方法參數傳遞的屬性,並覆蓋已讀取的同名屬性。
因此,通過方法參數傳遞的屬性具有最高優先級,resource/url屬性中指定的配置文件次之,最低優先級的是properties屬性中指定的屬性。

 settings

setting是指定MyBatis的一些全局配置屬性,這是MyBatis中極爲重要的調整設置,它們會改變MyBatis的運行時行爲,所以我們需要清楚的知道這些屬性的作用及默認值。

設置參數 描述 有效值 默認值
cacheEnabled 該配置影響的所有映射器中配置的緩存的全局開關 true | false true
lazyLoadingEnabled 延遲加載的全局開關。當開啓時,所有關聯對象都會延遲加載。 特定關聯關係中可通過設置fetchType屬性來覆蓋該項的開關狀態 true | false false
aggressiveLazyLoading 當啓用時,對任意延遲屬性的調用會使帶有延遲加載屬性的對象完整加載;反之,每種屬性將會按需加載。 true | false true
multipleResultSetsEnabled 是否允許單一語句返回多結果集(需要兼容驅動)。 true | false true
useColumnLabel 使用列標籤代替列名。不同的驅動在這方面會有不同的表現, 具體可參考相關驅動文檔或通過測試這兩種不同的模式來觀察所用驅動的結果。 true | false true
useGeneratedKeys 允許 JDBC 支持自動生成主鍵,需要驅動兼容。 如果設置爲 true 則這個設置強制使用自動生成主鍵,儘管一些驅動不能兼容但仍可正常工作(比如 Derby)。 true | false False
autoMappingBehavior 指定 MyBatis 應如何自動映射列到字段或屬性。 NONE 表示取消自動映射;PARTIAL 只會自動映射沒有定義嵌套結果集映射的結果集。 FULL 會自動映射任意複雜的結果集(無論是否嵌套)。 NONE, PARTIAL, FULL PARTIAL
defaultExecutorType 配置默認的執行器。SIMPLE 就是普通的執行器;REUSE 執行器會重用預處理語句(prepared statements); BATCH 執行器將重用語句並執行批量更新。 SIMPLE REUSE BATCH SIMPLE
defaultStatementTimeout 設置超時時間,它決定驅動等待數據庫響應的秒數。 Any positive integer Not Set (null)
defaultFetchSize Sets the driver a hint as to control fetching size for return results. This parameter value can be override by a query setting. Any positive integer Not Set (null)
safeRowBoundsEnabled 允許在嵌套語句中使用分頁(RowBounds)。 true | false False
mapUnderscoreToCamelCase 是否開啓自動駝峯命名規則(camel case)映射,即從經典數據庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的類似映射。 true | false False
localCacheScope MyBatis 利用本地緩存機制(Local Cache)防止循環引用(circular references)和加速重複嵌套查詢。 默認值爲 SESSION,這種情況下會緩存一個會話中執行的所有查詢。 若設置值爲 STATEMENT,本地會話僅用在語句執行上,對相同 SqlSession 的不同調用將不會共享數據。 SESSION | STATEMENT SESSION
jdbcTypeForNull 當沒有爲參數提供特定的 JDBC 類型時,爲空值指定 JDBC 類型。 某些驅動需要指定列的 JDBC 類型,多數情況直接用一般類型即可,比如 NULL、VARCHAR 或 OTHER。 JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER OTHER
lazyLoadTriggerMethods 指定哪個對象的方法觸發一次延遲加載。 A method name list separated by commas equals,clone,hashCode,toString
defaultScriptingLanguage 指定動態 SQL 生成的默認語言。 A type alias or fully qualified class name. org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
callSettersOnNulls 指定當結果集中值爲 null 的時候是否調用映射對象的 setter(map 對象時爲 put)方法,這對於有 Map.keySet() 依賴或 null 值初始化的時候是有用的。注意基本類型(int、boolean等)是不能設置成 null 的。 true | false false
logPrefix 指定 MyBatis 增加到日誌名稱的前綴。 Any String Not set
logImpl 指定 MyBatis 所用日誌的具體實現,未指定時將自動查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING Not set
proxyFactory 指定 Mybatis 創建具有延遲加載能力的對象所用到的代理工具。 CGLIB | JAVASSIST JAVASSIST (MyBatis 3.3 or above)

一個完整的settings元素示例如下:

[html] view plain copy
  1. <settings>  
  2.   <setting name="cacheEnabled" value="true"/>  
  3.   <setting name="lazyLoadingEnabled" value="true"/>  
  4.   <setting name="multipleResultSetsEnabled" value="true"/>  
  5.   <setting name="useColumnLabel" value="true"/>  
  6.   <setting name="useGeneratedKeys" value="false"/>  
  7.   <setting name="autoMappingBehavior" value="PARTIAL"/>  
  8.   <setting name="defaultExecutorType" value="SIMPLE"/>  
  9.   <setting name="defaultStatementTimeout" value="25"/>  
  10.   <setting name="defaultFetchSize" value="100"/>  
  11.   <setting name="safeRowBoundsEnabled" value="false"/>  
  12.   <setting name="mapUnderscoreToCamelCase" value="false"/>  
  13.   <setting name="localCacheScope" value="SESSION"/>  
  14.   <setting name="jdbcTypeForNull" value="OTHER"/>  
  15.   <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>  
  16. </settings>  

typeAliases

類型別名是爲Java類型設置一個短的名字。它只和xml配置有關,存在的意義僅在於用來減少類完全限定名的冗餘,例如:

[html] view plain copy
  1. <typeAliases>  
  2.   <typeAlias alias="Author" type="domain.blog.Author"/>  
  3.   <typeAlias alias="Blog" type="domain.blog.Blog"/>  
  4.   <typeAlias alias="Comment" type="domain.blog.Comment"/>  
  5.   <typeAlias alias="Post" type="domain.blog.Post"/>  
  6.   <typeAlias alias="Section" type="domain.blog.Section"/>  
  7.   <typeAlias alias="Tag" type="domain.blog.Tag"/>  
  8. </typeAliases>  
當這樣配置時,Blog可以用在任何使用domain.blog.Blog的地方。

也可以指定一個包名,MyBatis會在包名下搜索需要的JavaBean,比如:

[html] view plain copy
  1. <typeAliases>  
  2.   <package name="domain.blog"/>  
  3. </typeAliases>  
每一個在包domain.blog中的JavaBean,在沒有註解的情況下,會使用Bean的首字母小寫的非限類名來作爲它的別名。比如domain.blog.Author的別名爲author;若有註解,則別名爲註解值。看下面的例子:

[html] view plain copy
  1. @Alias("author") public class Author  
  2.     {  
  3. ...}  
已經爲許多常見的Java類型內建了相應的類型別名。它們都是大小寫不敏感的,需要注意的是有基本類型名稱重複導致的特殊處理。

別名 映射的類型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

typeHandlers

無論是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,還是從結果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型。下表描述了一些默認的類型處理器。

類型處理器 Java 類型 JDBC 類型
BooleanTypeHandler java.lang.Booleanboolean 數據庫兼容的 BOOLEAN
ByteTypeHandler java.lang.Bytebyte 數據庫兼容的 NUMERIC 或 BYTE
ShortTypeHandler java.lang.Shortshort 數據庫兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandler java.lang.Integerint 數據庫兼容的 NUMERIC 或 INTEGER
LongTypeHandler java.lang.Longlong 數據庫兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandler java.lang.Floatfloat 數據庫兼容的 NUMERIC 或 FLOAT
DoubleTypeHandler java.lang.Doubledouble 數據庫兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandler java.math.BigDecimal 數據庫兼容的 NUMERIC 或 DECIMAL
StringTypeHandler java.lang.String CHARVARCHAR
ClobTypeHandler java.lang.String CLOBLONGVARCHAR
NStringTypeHandler java.lang.String NVARCHARNCHAR
NClobTypeHandler java.lang.String NCLOB
ByteArrayTypeHandler byte[] 數據庫兼容的字節流類型
BlobTypeHandler byte[] BLOBLONGVARBINARY
DateTypeHandler java.util.Date TIMESTAMP
DateOnlyTypeHandler java.util.Date DATE
TimeOnlyTypeHandler java.util.Date TIME
SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP
SqlDateTypeHandler java.sql.Date DATE
SqlTimeTypeHandler java.sql.Time TIME
ObjectTypeHandler Any OTHER 或未指定類型 
EnumTypeHandler Enumeration Type  VARCHAR-任何兼容的字符串類型,存儲枚舉的名稱(而不是索引)
EnumOrdinalTypeHandler Enumeration Type 任何兼容的 NUMERIC 或 DOUBLE 類型,存儲枚舉的索引(而不是名稱)。 
     

可以重寫類型處理器或創建自己的類型處理器來處理不支持的或非標準的類型。具體的做法爲:實現org.apache.ibatis.type.TypeHandler接口,或繼承一個很便利的類org.apache.ibatis.type.BaseTypeHandler,然後可以選擇性地將它映射到一個JDBC類型。比如:

[html] view plain copy
  1.  //  
  2. ExampleTypeHandler.java  
  3. @MappedJdbcTypes(JdbcType.VARCHAR) public class ExampleTypeHandler extends BaseTypeHandler<String>  
  4.   
  5.   {  
  6.   
  7.   @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException  
  8.     { ps.setString(i,  
  9.   parameter)  
  10. ;  
  11.   }  
  12.   
  13.   @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException  
  14.     { return  
  15.   rs.getString(columnName)  
  16. ;  
  17.   }  
  18.   
  19.   @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException  
  20.     { return  
  21.   rs.getString(columnIndex)  
  22. ;  
  23.   }  
  24.   
  25.   @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException  
  26.     { return  
  27.   cs.getString(columnIndex);  
  28. }}  
並且還需要在配置文件裏面加上:

[html] view plain copy
  1. <!-- mybatis-config.xml -->  
  2. <typeHandlers>  
  3.   <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>  
  4. </typeHandlers>  
使用這個的類型處理器將會覆蓋已經存在的處理Java的String類型屬性和VARCHAR參數及結果的類型處理器。要注意MyBatis不會窺探數據庫元信息來決定使用哪種類型,所以必須在參數和結果映射中指明是VARCHAR類型字段,以使其能綁定到正確的類型處理器上。這是因爲,MyBatis直到語句被執行才清楚數據類型。
通過類型處理器的泛型,MyBatis可以得知該類型處理器的Java類型,不過這種行爲可以通過兩種方法改變:

  • 在類型處理器的元素(typeHandler element)上增加一個javaType屬性(比如,javaType="String");
  • 在類型處理器的類上(TypeHandler class)增加一個@MappedTypes註解來指定與其關聯的Java類型列表。如果在javaType屬性中也同時制定,則註解方式將被忽略。
可以通過兩種方式來指定被關聯的JDBC類型:

  • 在類型處理器的配置元素上增加一個javaType屬性(比如:javaType="VARCHAR");
  • 在類型處理器的類上(TypeHandler class)增加一個@MappedJdbcTypes註解來指定與其關聯的JDBC類型列表。如果在javaType屬性中也同時指定,則註解方式將被忽略。
最後,還可以讓MyBatis查找類型處理器:

[html] view plain copy
  1. <!-- mybatis-config.xml -->  
  2. <typeHandlers>  
  3.   <package name="org.mybatis.example"/>  
  4. </typeHandlers>  
注意在使用自動檢索(autodiscovery)功能的時候,只能通過註解的方式來指定JDBC類型。

你能創建一個泛型類型處理器,它可以處理多於一個類。爲達到此目的,需要增加一個接收該類作爲參數的構造器,這樣在構造一個類型處理器的時候MyBatis就會傳入一個具體的類。

[html] view plain copy
  1. //GenericTypeHandler.java public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E>  
  2.   
  3.   { private Class<E>  
  4.   
  5.   type; public GenericTypeHandler(Class<E> type){  
  6.     if (type == null) throw new IllegalArgumentException("Type argument cannot be null");  
  7.     this.type =   
  8.   type;}  
  9.   ...  
EnumTypeHandler和EnumOrdinalTypeHandler都是泛型處理器(generic TypeHandlers),接下來的部分詳細探討。

處理枚舉類型

若想映射枚舉類型Enum,則需要從EnumTypeHandler或者EnumOrdinalTypeHandler中選一個來使用

比如說我們想存儲近似值時用到的舍入模式。默認情況下,MyBatis會利用EnumTypeHandler來把Enum值轉換成對應的名字。

注意EnumTypeHandler在某種意義上來說是比較特別的,其他的處理器只針對某個特定的類,而它不同,它會處理任意繼承了Enum的類。

不過,我們可能不想存儲名字,相反我們的DBA會堅持使用整形值代碼。那也一樣輕而易舉;在配置文件中把EnumOrdinalTypeHandler加到typeHandlers中即可,這樣每個RoundingMode將通過他們的序數值來映射成對應的整形。

[html] view plain copy
  1. <!-- mybatis-config.xml -->  
  2. <typeHandlers>  
  3.   <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>  
  4. </typeHandlers>  
但是怎麼樣能將同樣的Enum既映射成字符串又映射成整形呢?

自動映射器(auto-mapper)會自動選用EnumOrdinalTypeHandler來處理,所以如果我們想用普通的EnumTypeHandler,就非要爲那些SQL語句顯示地設置要用到的類型處理器不可。

[html] view plain copy
  1. <!DOCTYPE mapper  
  2.     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  3.     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  4.   
  5.   
  6. <mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">  
  7.     <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">  
  8.         <id column="id" property="id"/>  
  9.         <result column="name" property="name"/>  
  10.         <result column="funkyNumber" property="funkyNumber"/>  
  11.         <result column="roundingMode" property="roundingMode"/>  
  12.     </resultMap>  
  13.   
  14.   
  15.     <select id="getUser" resultMap="usermap">  
  16.         select * from users  
  17.     </select>  
  18.     <insert id=  
  19.         "insert"> insert into users (id, name, funkyNumber, roundingMode) values  
  20.             ( #{id}, #{name}, #{funkyNumber},  
  21.         #{roundingMode})  
  22.     </insert>  
  23.           
  24.     <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">  
  25.         <id column="id" property="id"/>  
  26.         <result column="name" property="name"/>  
  27.         <result column="funkyNumber" property="funkyNumber"/>  
  28.         <result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>  
  29.     </resultMap>  
  30.     <select id="getUser2" resultMap="usermap2">  
  31.         select * from users2  
  32.     </select>  
  33.     <insert id=  
  34.         "insert2"> insert into users2 (id, name, funkyNumber, roundingMode) values(  
  35.             #{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=  
  36.         org.apache.ibatis.type.EnumTypeHandler})  
  37.     </insert>  
  38.   
  39.   
  40. </mapper>  
注意,這裏的select語句強制使用resultMap來代替resultType。

對象工廠(objectFactory)

MyBatis每次創建結果對象的新實例時,它都會使用一個對象工廠(ObjectFactory)實例來完成。默認的對象工廠需要做的僅僅是實例化目標類,要麼通過默認構造方法,要麼在參數映射存在的時候通過參數構造方法來實例化。如果想覆蓋對象工廠的行爲,則可以通過創建自己的對象工廠來實現,比如:

[html] view plain copy
  1. //  
  2. xampleObjectFactory.java public class ExampleObjectFactory extends DefaultObjectFactory  
  3.  { public Object create(Class type)  
  4.    { return  
  5.  super.create(type);  
  6.  } public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs)  
  7.    { return super.create(type, constructorArgTypes,  
  8.  constructorArgs);  
  9.  } public void setProperties(Properties properties)  
  10.    {  
  11.  super.setProperties(properties);  
  12.  } public <T> boolean isCollection(Class<T> type){  
  13.    return Collection.class.isAssignableFrom(type);  
  14.  }}  
[html] view plain copy
  1. <!-- mybatis-config.xml -->  
  2. <objectFactory type="org.mybatis.example.ExampleObjectFactory">  
  3.   <property name="someProperty" value="100"/>  
  4. </objectFactory>  
ObjectFactory接口很簡單,它包含兩個創建用的方法,一個是處理默認構造方法的,另外一個是處理帶參數的構造方法。最後setProperties方法可以被用來配置ObjectFactory,初始化你的ObjectFactory實例後,objectFactory元素體內定義的屬性會被傳遞給setProperties方法。

插件(plugins)

MyBatis允許你在已映射的語句執行過程中的某一點進行攔截調用。默認情況下,Mybatis允許使用插件來攔截的方法調用包括:

  • Executor(update,query,flushStatements,commit,rollback,getTransaction,close,isClosed)
  • ParameterHandler(getParameterObejct,setParameters)
  • ResultSetHandler(handlerResultSets,handlerOutputParameters)
  • StatementHandler(prepare,parameterize,batch,update,query)
這些類中方法的細節可以通過查看每個方法的簽名來發現,或者直接查看MyBatis的發行包中的源代碼。假設你想做的不僅僅是方法的調用,那麼你應該很好的瞭解正在重寫的方法的行爲。因爲如果在視圖修改或重寫已有方法的行爲的時候,你很有可能在破壞MyBatis的核心模塊。這些都是更低層的類和方法,所以使用插件的時候要特別擔心。

通過MyBatis提供強大的機制,使用插件是非常簡單的,只需要實現Interceptor接口,並指定想要攔截的方法簽名即可。

[html] view plain copy
  1. // ExamplePlugin.java  
  2. @Intercepts({@Signature(  
  3.   typeExecutor.class,  
  4.   method = "update",  
  5.   args =   
  6. {MappedStatement.class,Object.class})}) public class ExamplePlugin implements Interceptor  
  7.   { public Object intercept(Invocation invocation) throws Throwable  
  8.     { return  
  9.   invocation.proceed();  
  10.   } public Object plugin(Object target)  
  11.     { return Plugin.wrap(target,  
  12.   this);  
  13.   } public void setProperties(Properties properties)  
  14.   {}  
  15. }  
[html] view plain copy
  1. <!-- mybatis-config.xml -->  
  2. <plugins>  
  3.   <plugin interceptor="org.mybatis.example.ExamplePlugin">  
  4.     <property name="someProperty" value="100"/>  
  5.   </plugin>  
  6. </plugins>  
上面的插件將會攔截Executor實例中所有的“update”方法調用,這裏的Executor是負責執行底層映射語句的內部對象。
覆蓋配置類

除了用插件來修改MyBatis核心行爲之外,還可以通過完全覆蓋配置類來達到目的。只需繼承後覆蓋其中的每個方法,再把它傳遞到sqlSessionFactoryBuilder.build(myConfig)方法即可。再次重申,這可能會嚴重影響Mybatis的行爲,務請慎之又慎!

配置環境(environments)

MyBatis可以配置成適應多種環境,這種機制有助於將sql映射應用於多種數據庫中,現實情況下有多種理由需要這麼做。例如,開發、測試和生產環境需要有不同的配置;或者共享相同的Schema的多個生產數據庫,想使用相同的sql映射。許多類似的用例。
儘管可以配置多個環境,但是每個SqlSessionFactory實例只能選擇其一。
所以,如果想連接兩個數據庫,就需要創建兩個SqlSessionFactory實例,每個數據庫對應一個。而如果是三個數據庫,就需要三個實例,依此類推。

每個數據庫對應一個SqlSessionFactory實例

爲了指定創建哪種環境,只要將它作爲可選參數傳遞給SqlSessionFactoryBuilder即可。可以接受環境配置的兩個方法簽名是:

[html] view plain copy
  1. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);  
  2. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);  
如果忽略了環境參數,那麼默認環境將會被加載,如下所示:
[html] view plain copy
  1. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);  
  2. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);  
環境元素定義瞭如何配置環境

[html] view plain copy
  1. <environments default="development">  
  2.   <environment id="development">  
  3.     <transactionManager type="JDBC">  
  4.       <property name="..." value="..."/>  
  5.     </transactionManager>  
  6.     <dataSource type="POOLED">  
  7.       <property name="driver" value="${driver}"/>  
  8.       <property name="url" value="${url}"/>  
  9.       <property name="username" value="${username}"/>  
  10.       <property name="password" value="${password}"/>  
  11.     </dataSource>  
  12.   </environment>  
  13. </environments>  
注意這裏的關鍵點:

  • 默認環境的ID(比如:default="development")
  • 每個environment元素定義的環境ID(比如:id="development")
  • 事務管理器的配置(比如:type="JDBC")
  • 數據源的配置(比如:type="POOLED")
默認的環境和環境ID是一目瞭然的。隨你怎麼命名,只要保證默認環境要匹配其中一個環境ID
事務管理器(transactionManager)

在MyBatis中有兩種類型的事務管理器(也就是 type="[JDBC|MANAGED]")

  • JDBC --- 這個配置就是直接使用了JDBC的提交和回滾設置,它依賴於從數據源得到的連接來管理事務範圍。
  • MANAGED --- 這個配置幾乎沒做什麼。它從來不提交或回滾一個連接,而是讓容器來管理事務的整個生命週期(比如JEE應用服務器上下文)。默認情況下它會關閉連接,然而一些容器並不希望這樣,因此需要將closeConnection屬性設置爲false來阻止它默認的行爲。例如
[html] view plain copy
  1. <transactionManager type="MANAGED">  
  2.   <property name="closeConnection" value="false"/>  
  3. </transactionManager>  
如果正在使用Spring+MyBatis,則沒有必要配置事務管理器,因爲Spring模塊會使用自帶的管理器來覆蓋前面的配置。
這兩種事務管理器類型都不需要任何屬性。它們只不過是類型別名,換句話說,你可以使用TransactionFactory接口的實現類的完全限定名或類型別名替代它們。

[html] view plain copy
  1. public interface TransactionFactory{  
  2.   void setProperties(Properties props);     
  3.   Transaction newTransaction(Connection conn);  
  4.   Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);     
  5. }  
任何在xml中配置的屬性在實例化之後將會被傳遞給setProperties方法。你也需要創建一個Transaction接口的實現類,這個接口也很簡單。

[html] view plain copy
  1. public interface Transaction{  
  2.  Connection getConnection() throws SQLException;  
  3.  void commit() throws SQLException;  
  4.  void rollback() throws SQLException;  
  5.  void close() throws SQLException;  
使用這兩個接口,完全可以自定義MyBatis對事務的處理。
數據源(dataSource)
dataSource元素使用了標準的JDBC數據源接口來配置JDBC連接對象的資源。

  • 許多MyBatis的應用程序將會按示例中的例子來配置數據源。然而它並不是必須的。要知道爲了方便使用延遲加載,數據源纔是必須的。
有三種內建的數據源類型(也就是 type="[]UNPOOLED|POOLED|JNDI]");

UNPOOLED --- 這個數據源的實現只是被請求時打開和關閉連接。雖然有一點慢,它對在及時可用連接方面沒有性能要求的簡單應用是一個很好的選擇。不同的數據庫在這方面表現也是不一樣的,所以對某些數據庫來說使用連接池並不重要,這個配置也是理想。UNPOOLED類型的數據源僅僅需要配置以下5種屬性:

  • driver  -- 這是JDBC驅動的Java類的完全限定名(並不是JDBC驅動中可能包含的數據源類)
  • url -- 這是數據庫的JDBC URL 地址。
  • username -- 登錄數據庫的用戶名。
  • password -- 登錄數據庫的密碼。
  • defaultTransactionIsolationLevel -- 默認的連接事務隔離級別。
作爲可選項,可以傳遞屬性給數據庫驅動。要這樣做,屬性的前綴爲"driver.",例如:

  • driver.encoding=UTF-8

這將通過DriverManager,getConnection(url,driverProperties)方法傳遞值爲UTF-8的encoding屬性給數據庫驅動。

POOLED --- 這種數據源的實現利用“池”的概念將JDBC連接對象組織起來,避免了創建新的連接實例時所必需的初始化和認證時間。這是一種使得併發web應用快速響應請求的流行處理方式。

除了上述提到UNPOOLED下的屬性外,會有更多屬性用來配置POOLED的數據源:

  • poolMaximumActiveConnections  -- 在任意時間可以存在的活動(也就是正在使用)連接數量,默認值10
  • poolMaximumIdleConnections  -- 任意時間可能存在的空閒連接數。
  • poolMaximumCheckoutTime  -- 在被強制返回之前,池中連接被檢出(checked out)時間,默認值:20000毫秒(即20秒)
  • poolTimeToWait  -- 這是一個底層設置,如果獲取連接花費的相當長的時間,它會給連接池打印狀態日誌並重新嘗試獲取一個連接(避免在誤配置的情況下一直安靜的失敗),默認值20000毫秒(即20秒)。
  • poolPingQuery  -- 發送到數據庫的偵測查詢,用來檢驗連接是否處在正常的工作秩序中,並且準備接受請求。默認是"NOT PING QUERY SET",這會導致多數數據庫連接失敗時帶有一個恰當的錯誤信息。
  • poolPingEnabled  -- 是否啓用偵測。若開啓,也必須使用一個可執行的SQL語句設置poolPingQuery屬性(最好是一個非常快的SQL),默認值:false。
  • poolPingConnectionsNotUsedFor  -- 配置poolPingQuery使用的頻度。這可以被設置成匹配具體的數據庫連接超時時間,來避免不必要的偵測,默認值:0(即所有連接每一時刻都被偵測  --  當然僅當 poolPingEnabled爲true時適用)。
JNDI  -- 這個數據源的實現是爲了能在如EJB或應用服務器這類容器中使用,容器可以集中或在外部配置數據源,然後放置一個JNDI上下文的引用。這種數據源配置只要兩個屬性:
  • initial_context  -- 這個屬性用來在InitialContext中尋找上下文(即,initialContext.lookup(initial_context))。這是個可選屬性,如果忽略,那麼data_source屬性將會直接從InitialContext中尋找。
  • data_source  -- 這是引用數據源實例位置的上下文的路徑。提供了 initial_context配置時會在其返回的上下文中進行查找,沒有提供時則直接在InitialContext中查找。
和其他數據源配置類似,可以通過添加前綴"env."直接把屬性傳遞給初始上下文。比如:
  • env.encoding=UTF-8
這會在初始上下文(InitialContext)實例化時往它的構造方法傳遞值爲UTF-8的encoding屬性。
通過需要實現接口 org.apache.ibatis.datasource.DataSourceFactory,也可使用任何第三方數據源,:
[html] view plain copy
  1. public interface DataSourceFactory{  
  2.  void setProperties(Properties props);  
  3.  DataSource getDataSource();  
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory 可被用作父類來構建新的數據源適配器,比如下面這段插入C3P0所必需的代碼:
[html] view plain copy
  1.  import  
  2. org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory; import  
  3.           
  4. com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0DataSourceFactory extends UnpooledDataSourceFactory  
  5.   
  6.   { public C3P0DataSourceFactory(){  
  7.     this.dataSource =  new  
  8.   ComboPooledDataSource();}  
  9. }  
爲了令其工作,爲每個需要MyBatis調用的setter方法中增加一個屬性。下面是一個可以連接到PostgreSQL數據庫的例子:
[html] view plain copy
  1. <dataSource type="org.myproject.C3P0DataSourceFactory">  
  2.   <property name="driver" value="org.postgresql.Driver"/>  
  3.   <property name="url" value="jdbc:postgresql:mydb"/>  
  4.   <property name="username" value="postgres"/>  
  5.   <property name="password" value="root"/>  
  6. </dataSource>  

databaseIdProvider

MyBatis可以根據不同的數據庫廠商執行不同的語句,這種多廠商的支持是基於映射語句中的databaseId屬性。MyBatis會加載不帶databaseId屬性和帶有匹配當前數據庫databaseId屬性的所有語句。如果同時找到帶有databaseId和不帶databaseId的相同語句,則後者被捨棄。爲支持多廠商特性,只要像下面這樣在mybatis-config.xml文件中加入databaseIdProvider即可:
[html] view plain copy
  1. <databaseIdProvider type="DB_VENDOR" />  
這裏的DB_VENDOR會通過DatabaseMetaData#getDatabaseProductName()返回的字符串進行設置。由於通常情況下這個字符串都非常長而且相同產品的不同版本會返回不同的值,所以最好通過設置屬性別名來使其變短,如下:
[html] view plain copy
  1. <databaseIdProvider type="DB_VENDOR">  
  2.   <property name="SQL Server" value="sqlserver"/>  
  3.   <property name="DB2" value="db2"/>           
  4.   <property name="Oracle" value="oracle" />  
  5. </databaseIdProvider>  
在有properties時,DB_VENDOR databaseIdProvider的將被設置爲第一個能匹配數據庫產品名稱的屬性鍵值對應的值,如果沒有匹配的屬性將會設置爲”null“。在這個例子中,如果getDatabaseProductName()返回”Oracle(DataDirect)“,databaseId將被設置爲"oracle"。
可以通過實現接口org.apache.ibatis.mapping.DatabaseIdProvider並在mybatis-config.xml中註冊來構建自己的DatabaseIdProvider:
[html] view plain copy
  1. public interface DatabaseIdProvider{  
  2.   void setProperties(Properties p);  
  3.   String getDatabaseId(DataSource dataSource) throws SQLException;  
  4. }  

映射器(mappers)

既然MyBatis的行爲已經由上述元素配置完了,現在就要定義SQL映射語句了。但是首先需要告訴MyBatis到哪裏去找到這些語句。Java在自動查找這方面沒有提供一個很好的方法,所以最佳的方式是告訴MyBatis到哪裏去找映射文件。可以使用相對於類路徑的資源引用、或完全限定資源定位符(包括file:///的URL),或類名和包名等等。例如:
[html] view plain copy
  1. <!-- Using classpath relative resources -->  
  2. <mappers>  
  3.   <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>  
  4.   <mapper resource="org/mybatis/builder/BlogMapper.xml"/>  
  5.   <mapper resource="org/mybatis/builder/PostMapper.xml"/>  
  6. </mappers>  
[html] view plain copy
  1. <!-- Using url fully qualified paths -->  
  2. <mappers>  
  3.   <mapper url="file:///var/mappers/AuthorMapper.xml"/>  
  4.   <mapper url="file:///var/mappers/BlogMapper.xml"/>  
  5.   <mapper url="file:///var/mappers/PostMapper.xml"/>  
  6. </mappers>  
[html] view plain copy
  1. <!-- Using mapper interface classes -->  
  2. <mappers>  
  3.   <mapper class="org.mybatis.builder.AuthorMapper"/>  
  4.   <mapper class="org.mybatis.builder.BlogMapper"/>  
  5.   <mapper class="org.mybatis.builder.PostMapper"/>  
  6. </mappers>  
[html] view plain copy
  1. <!-- Register all interfaces in a package as mappers -->  
  2. <mappers>  
  3.   <package name="org.mybatis.builder"/>  
  4. </mappers>  
這些配置會告訴了MyBatis去哪裏找映射文件,剩下的細節就應該是每個SQL映射文件了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章