mybatis-xml配置

XML 映射配置文件

MyBatis 的配置文件包含了影響 MyBatis 行爲甚深的設置(settings)和屬性(properties)信息。文檔的頂層結構以下:html

properties

這些屬性都是可外部配置且可動態替換的,既能夠在典型的 Java 屬性文件中配置,亦可經過 properties 元素的子元素來傳遞。例如:java

<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>

其中的屬性就能夠在整個配置文件中使用來替換須要動態配置的屬性值。好比:git

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

這個例子中的 username 和 password 將會由 properties 元素中設置的相應值來替換。 driver 和 url 屬性將會由 config.properties 文件中對應的值來替換。這樣就爲配置提供了諸多靈活選擇。github

屬性也能夠被傳遞到 SqlSessionBuilder.build()方法中。例如:sql

SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props);

// ... or ...

SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);

若是屬性在不僅一個地方進行了配置,那麼 MyBatis 將按照下面的順序來加載:數據庫

  • 在 properties 元素體內指定的屬性首先被讀取。
  • 而後根據 properties 元素中的 resource 屬性讀取類路徑下屬性文件或根據 url 屬性指定的路徑讀取屬性文件,並覆蓋已讀取的同名屬性。
  • 最後讀取做爲方法參數傳遞的屬性,並覆蓋已讀取的同名屬性。

所以,經過方法參數傳遞的屬性具備最高優先級,resource/url 屬性中指定的配置文件次之,最低優先級的是 properties 屬性中指定的屬性。apache

settings

這是 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
autoMappingUnknownColumnBehavior Specify the behavior when detects an unknown column (or unknown property type) of automatic mapping target.
  • NONE: Do nothing
  • WARNING: Output warning log (The log level of'org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' must be set toWARN)
  • FAILING: Fail mapping (Throw SqlSessionException)
NONE, WARNING, FAILING NONE
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)。 If allow, set the false. true | false False
safeResultHandlerEnabled 容許在嵌套語句中使用分頁(ResultHandler)。 If allow, set the false. true | false True
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)
vfsImpl Specifies VFS implementations Fully qualified class names of custom VFS implementation separated by commas. Not set
useActualParamName Allow referencing statement parameters by their actual names declared in the method signature. To use this feature, your project must be compiled in Java 8 with -parameters option. (Since: 3.4.1) true | false true

一個配置完整的 settings 元素的示例以下:服務器

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

typeAliases

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

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

當這樣配置時,Blog能夠用在任何使用domain.blog.Blog的地方。

也能夠指定一個包名,MyBatis 會在包名下面搜索須要的 Java Bean,好比:

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每個在包 domain.blog 中的 Java Bean,在沒有註解的狀況下,會使用 Bean 的首字母小寫的非限定類名來做爲它的別名。 好比 domain.blog.Author 的別名爲 author;如有註解,則別名爲其註解值。看下面的例子:

@Alias("author")
public class Author {
    ...
}

已經爲許多常見的 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 類型。下表描述了一些默認的類型處理器。

NOTE If you use classes provided by JSR-310(Date and Time API), you can use the mybatis-typehandlers-jsr310.

類型處理器 Java 類型 JDBC 類型
BooleanTypeHandler java.lang.Boolean, boolean 數據庫兼容的 BOOLEAN
ByteTypeHandler java.lang.Byte, byte 數據庫兼容的 NUMERIC 或 BYTE
ShortTypeHandler java.lang.Short, short 數據庫兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandler java.lang.Integer, int 數據庫兼容的 NUMERIC 或 INTEGER
LongTypeHandler java.lang.Long, long 數據庫兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandler java.lang.Float, float 數據庫兼容的 NUMERIC 或 FLOAT
DoubleTypeHandler java.lang.Double, double 數據庫兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandler java.math.BigDecimal 數據庫兼容的 NUMERIC 或 DECIMAL
StringTypeHandler java.lang.String CHAR, VARCHAR
ClobReaderTypeHandler java.io.Reader -
ClobTypeHandler java.lang.String CLOB, LONGVARCHAR
NStringTypeHandler java.lang.String NVARCHAR, NCHAR
NClobTypeHandler java.lang.String NCLOB
BlobInputStreamTypeHandler java.io.InputStream -
ByteArrayTypeHandler byte[] 數據庫兼容的字節流類型
BlobTypeHandler byte[] BLOB, LONGVARBINARY
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 類型。好比:

// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
    ps.setString(i, parameter);
  }

  @Override
  public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return rs.getString(columnName);
  }

  @Override
  public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    return rs.getString(columnIndex);
  }

  @Override
  public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    return cs.getString(columnIndex);
  }
}
<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

使用這個的類型處理器將會覆蓋已經存在的處理 Java 的 String 類型屬性和 VARCHAR 參數及結果的類型處理器。 要注意 MyBatis 不會窺探數據庫元信息來決定使用哪一種類型,因此你必須在參數和結果映射中指明那是 VARCHAR 類型的字段, 以使其可以綁定到正確的類型處理器上。 這是由於:MyBatis 直到語句被執行才清楚數據類型。

經過類型處理器的泛型,MyBatis 能夠得知該類型處理器處理的 Java 類型,不過這種行爲能夠經過兩種方法改變:

  • 在類型處理器的配置元素(typeHandler element)上增長一個 javaType 屬性(好比:javaType="String");
  • 在類型處理器的類上(TypeHandler class)增長一個 @MappedTypes 註解來指定與其關聯的 Java 類型列表。 若是在 javaType 屬性中也同時指定,則註解方式將被忽略。

能夠經過兩種方式來指定被關聯的 JDBC 類型:

  • 在類型處理器的配置元素上增長一個 jdbcType 屬性(好比:jdbcType="VARCHAR");
  • 在類型處理器的類上(TypeHandler class)增長一個 @MappedJdbcTypes 註解來指定與其關聯的 JDBC 類型列表。 若是在 jdbcType 屬性中也同時指定,則註解方式將被忽略。

When deciding which TypeHandler to use in a ResultMap, the Java type is known (from the result type), but the JDBC type is unknown. MyBatis therefore uses the combination javaType=[TheJavaType], jdbcType=null to choose a TypeHandler. This means that using a @MappedJdbcTypes annotation restricts the scope of a TypeHandler and makes it unavailable for use in ResultMaps unless explicity set. To make a TypeHandler available for use in a ResultMap, setincludeNullJdbcType=true on the @MappedJdbcTypes annotation. Since Mybatis 3.4.0 however, if a single TypeHandler is registered to handle a Java type, it will be used by default in ResultMaps using this Java type (i.e. even withoutincludeNullJdbcType=true).

最後,可讓 MyBatis 爲你查找類型處理器:

<!-- mybatis-config.xml -->
<typeHandlers>
  <package name="org.mybatis.example"/>
</typeHandlers>

注意在使用自動檢索(autodiscovery)功能的時候,只能經過註解方式來指定 JDBC 的類型。

你能建立一個泛型類型處理器,它能夠處理多於一個類。爲達到此目的, 須要增長一個接收該類做爲參數的構造器,這樣在構造一個類型處理器的時候 MyBatis 就會傳入一個具體的類。

//GenericTypeHandler.java
public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {

  private Class<E> type;

  public GenericTypeHandler(Class<E> type) {
    if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
    this.type = type;
  }
  ...

EnumTypeHandler 和 EnumOrdinalTypeHandler 都是泛型類型處理器(generic TypeHandlers), 咱們將會在接下來的部分詳細探討。

處理枚舉類型

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

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

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

不過,咱們可能不想存儲名字,相反咱們的 DBA 會堅持使用整形值代碼。那也同樣垂手可得: 在配置文件中把 EnumOrdinalTypeHandler 加到 typeHandlers 中便可, 這樣每一個 RoundingMode 將經過他們的序數值來映射成對應的整形。

<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
</typeHandlers>

可是怎樣能將一樣的 Enum 既映射成字符串又映射成整形呢?

自動映射器(auto-mapper)會自動地選用 EnumOrdinalTypeHandler 來處理, 因此若是咱們想用普通的 EnumTypeHandler,就非要爲那些 SQL 語句顯式地設置要用到的類型處理器不可。

(下一節纔開始講映射器文件,因此若是是首次閱讀該文檔,你可能須要先越過這一步,過會再來看。)

<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
	<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<result column="funkyNumber" property="funkyNumber"/>
		<result column="roundingMode" property="roundingMode"/>
	</resultMap>

	<select id="getUser" resultMap="usermap">
		select * from users
	</select>
	<insert id="insert">
	    insert into users (id, name, funkyNumber, roundingMode) values (
	    	#{id}, #{name}, #{funkyNumber}, #{roundingMode}
	    )
	</insert>
	
	<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<result column="funkyNumber" property="funkyNumber"/>
		<result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
	</resultMap>
	<select id="getUser2" resultMap="usermap2">
		select * from users2
	</select>
	<insert id="insert2">
	    insert into users2 (id, name, funkyNumber, roundingMode) values (
	    	#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
	    )
	</insert>

</mapper>

注意,這裏的 select 語句強制使用 resultMap 來代替 resultType。

對象工廠(objectFactory)

MyBatis 每次建立結果對象的新實例時,它都會使用一個對象工廠(ObjectFactory)實例來完成。 默認的對象工廠須要作的僅僅是實例化目標類,要麼經過默認構造方法,要麼在參數映射存在的時候經過參數構造方法來實例化。 若是想覆蓋對象工廠的默認行爲,則能夠經過建立本身的對象工廠來實現。好比:

// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
  public Object create(Class type) {
    return super.create(type);
  }
  public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {
    return super.create(type, constructorArgTypes, constructorArgs);
  }
  public void setProperties(Properties properties) {
    super.setProperties(properties);
  }
  public <T> boolean isCollection(Class<T> type) {
    return Collection.class.isAssignableFrom(type);
  }}
<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
  <property name="someProperty" value="100"/>
</objectFactory>

ObjectFactory 接口很簡單,它包含兩個建立用的方法,一個是處理默認構造方法的,另一個是處理帶參數的構造方法的。 最後,setProperties 方法能夠被用來配置 ObjectFactory,在初始化你的 ObjectFactory 實例後, objectFactory 元素體中定義的屬性會被傳遞給 setProperties 方法。

插件(plugins)

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

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

這些類中方法的細節能夠經過查看每一個方法的簽名來發現,或者直接查看 MyBatis 的發行包中的源代碼。 假設你想作的不只僅是監控方法的調用,那麼你應該很好的瞭解正在重寫的方法的行爲。 由於若是在試圖修改或重寫已有方法的行爲的時候,你極可能在破壞 MyBatis 的核心模塊。 這些都是更低層的類和方法,因此使用插件的時候要特別小心。

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

// ExamplePlugin.java
@Intercepts({@Signature(
  type= Executor.class,
  method = "update",
  args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
  public Object intercept(Invocation invocation) throws Throwable {
    return invocation.proceed();
  }
  public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  public void setProperties(Properties properties) {
  }
}
<!-- mybatis-config.xml -->
<plugins>
  <plugin interceptor="org.mybatis.example.ExamplePlugin">
    <property name="someProperty" value="100"/>
  </plugin>
</plugins>

上面的插件將會攔截在 Executor 實例中全部的 「update」 方法調用, 這裏的 Executor 是負責執行低層映射語句的內部對象。

NOTE 覆蓋配置類

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

配置環境(environments)

MyBatis 能夠配置成適應多種環境,這種機制有助於將 SQL 映射應用於多種數據庫之中, 現實狀況下有多種理由須要這麼作。例如,開發、測試和生產環境須要有不一樣的配置;或者共享相同 Schema 的多個生產數據庫, 想使用相同的 SQL 映射。許多相似的用例。

不過要記住:儘管能夠配置多個環境,每一個 SqlSessionFactory 實例只能選擇其一。

因此,若是你想鏈接兩個數據庫,就須要建立兩個 SqlSessionFactory 實例,每一個數據庫對應一個。而若是是三個數據庫,就須要三個實例,依此類推,記起來很簡單:

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

爲了指定建立哪一種環境,只要將它做爲可選的參數傳遞給 SqlSessionFactoryBuilder 便可。能夠接受環境配置的兩個方法簽名是:

SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);

若是忽略了環境參數,那麼默認環境將會被加載,以下所示:

SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);

環境元素定義瞭如何配置環境。

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </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>

注意這裏的關鍵點:

  • 默認的環境 ID(好比:default=」development」)。
  • 每一個 environment 元素定義的環境 ID(好比:id=」development」)。
  • 事務管理器的配置(好比:type=」JDBC」)。
  • 數據源的配置(好比:type=」POOLED」)。

默認的環境和環境 ID 是一目瞭然的。隨你怎麼命名,只要保證默認環境要匹配其中一個環境ID。

事務管理器(transactionManager)

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

  • JDBC – 這個配置就是直接使用了 JDBC 的提交和回滾設置,它依賴於從數據源獲得的鏈接來管理事務範圍。
  • MANAGED – 這個配置幾乎沒作什麼。它歷來不提交或回滾一個鏈接,而是讓容器來管理事務的整個生命週期(好比 JEE 應用服務器的上下文)。 默認狀況下它會關閉鏈接,然而一些容器並不但願這樣,所以須要將 closeConnection 屬性設置爲 false 來阻止它默認的關閉行爲。例如:
    <transactionManager type="MANAGED">
      <property name="closeConnection" value="false"/>
    </transactionManager>

NOTE若是你正在使用 Spring + MyBatis,則沒有必要配置事務管理器, 由於 Spring 模塊會使用自帶的管理器來覆蓋前面的配置。

這兩種事務管理器類型都不須要任何屬性。它們不過是類型別名,換句話說,你可使用 TransactionFactory 接口的實現類的徹底限定名或類型別名代替它們。

public interface TransactionFactory {
  void setProperties(Properties props);  
  Transaction newTransaction(Connection conn);
  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);  
}

任何在 XML 中配置的屬性在實例化以後將會被傳遞給 setProperties() 方法。你也須要建立一個 Transaction 接口的實現類,這個接口也很簡單:

public interface Transaction {
  Connection getConnection() throws SQLException;
  void commit() throws SQLException;
  void rollback() throws SQLException;
  void close() throws SQLException;
  Integer getTimeout() 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=UTF8

這將經過DriverManager.getConnection(url,driverProperties)方法傳遞值爲 UTF8 的 encoding 屬性給數據庫驅動。

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

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

  • poolMaximumActiveConnections – 在任意時間能夠存在的活動(也就是正在使用)鏈接數量,默認值:10
  • poolMaximumIdleConnections – 任意時間可能存在的空閒鏈接數。
  • poolMaximumCheckoutTime – 在被強制返回以前,池中鏈接被檢出(checked out)時間,默認值:20000 毫秒(即 20 秒)
  • poolTimeToWait – 這是一個底層設置,若是獲取鏈接花費的至關長的時間,它會給鏈接池打印狀態日誌並從新嘗試獲取一個鏈接(避免在誤配置的狀況下一直安靜的失敗),默認值:20000 毫秒(即 20 秒)。
  • poolPingQuery – 發送到數據庫的偵測查詢,用來檢驗鏈接是否處在正常工做秩序中並準備接受請求。默認是「NO 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=UTF8

這就會在初始上下文(InitialContext)實例化時往它的構造方法傳遞值爲 UTF8 的 encoding 屬性。

經過須要實現接口 org.apache.ibatis.datasource.DataSourceFactory , 也可以使用任何第三方數據源,:

public interface DataSourceFactory {
  void setProperties(Properties props);
  DataSource getDataSource();
}

org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory 可被用做父類來構建新的數據源適配器,好比下面這段插入 C3P0 數據源所必需的代碼:

import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
        
public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {

  public C3P0DataSourceFactory() {
    this.dataSource = new ComboPooledDataSource();
  }
}

爲了令其工做,爲每一個須要 MyBatis 調用的 setter 方法中增長一個屬性。下面是一個能夠鏈接至 PostgreSQL 數據庫的例子:

<dataSource type="org.myproject.C3P0DataSourceFactory">
  <property name="driver" value="org.postgresql.Driver"/>
  <property name="url" value="jdbc:postgresql:mydb"/>
  <property name="username" value="postgres"/>
  <property name="password" value="root"/>
</dataSource>

databaseIdProvider

MyBatis 能夠根據不一樣的數據庫廠商執行不一樣的語句,這種多廠商的支持是基於映射語句中的 databaseId 屬性。 MyBatis 會加載不帶 databaseId 屬性和帶有匹配當前數據庫 databaseId 屬性的全部語句。 若是同時找到帶有 databaseId 和不帶 databaseId 的相同語句,則後者會被捨棄。 爲支持多廠商特性只要像下面這樣在 mybatis-config.xml 文件中加入 databaseIdProvider 便可:

<databaseIdProvider type="DB_VENDOR" />

這裏的 DB_VENDOR 會經過 DatabaseMetaData#getDatabaseProductName() 返回的字符串進行設置。 因爲一般狀況下這個字符串都很是長並且相同產品的不一樣版本會返回不一樣的值,因此最好經過設置屬性別名來使其變短,以下:

<databaseIdProvider type="DB_VENDOR">
  <property name="SQL Server" value="sqlserver"/>
  <property name="DB2" value="db2"/>        
  <property name="Oracle" value="oracle" />
</databaseIdProvider>

在有 properties 時,DB_VENDOR databaseIdProvider 的將被設置爲第一個能匹配數據庫產品名稱的屬性鍵對應的值,若是沒有匹配的屬性將會設置爲 「null」。 在這個例子中,若是 getDatabaseProductName() 返回「Oracle (DataDirect)」,databaseId 將被設置爲「oracle」。

你能夠經過實現接口 org.apache.ibatis.mapping.DatabaseIdProvider 並在 mybatis-config.xml 中註冊來構建本身的 DatabaseIdProvider:

public interface DatabaseIdProvider {
  void setProperties(Properties p);
  String getDatabaseId(DataSource dataSource) throws SQLException;
}

映射器(mappers)

既然 MyBatis 的行爲已經由上述元素配置完了,咱們如今就要定義 SQL 映射語句了。可是首先咱們須要告訴 MyBatis 到哪裏去找到這些語句。 Java 在自動查找這方面沒有提供一個很好的方法,因此最佳的方式是告訴 MyBatis 到哪裏去找映射文件。你可使用相對於類路徑的資源引用, 或徹底限定資源定位符(包括 file:/// 的 URL),或類名和包名等。例如:

<!-- Using classpath relative resources -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- Using url fully qualified paths -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- Using mapper interface classes -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- Register all interfaces in a package as mappers -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

這些配置會告訴了 MyBatis 去哪裏找映射文件,剩下的細節就應該是每一個 SQL 映射文件了,也就是接下來咱們要討論的。

相關文章
相關標籤/搜索