Mybatis-Configuration-詳解

Configuration

MyBatis的初始化會執行SqlSessionFactoryBuilder的中build()方法,build方法又會調用XMLConfigBuilder()的內部parse()方法進行加載配置,因此咱們先看一下parse()的源碼:java

public Configuration parse() {
  if (parsed) {
    throw new BuilderException("Each XMLConfigBuilder can only be used once.");
  }
  parsed = true;
  parseConfiguration(parser.evalNode("/configuration"));//真正執行的加載配置的是這個方法
  return configuration;
}sql

private void parseConfiguration(XNode root) {
  try {
    //issue #117 read properties first
   
propertiesElement(root.evalNode("properties"));
    Properties settings = settingsAsProperties(root.evalNode("settings"));
    loadCustomVfs(settings);
    typeAliasesElement(root.evalNode("typeAliases"));
    pluginElement(root.evalNode("plugins"));
    objectFactoryElement(root.evalNode("objectFactory"));
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    reflectorFactoryElement(root.evalNode("reflectorFactory"));
    settingsElement(settings);
    // read it after objectFactory and objectWrapperFactory issue #631
   
environmentsElement(root.evalNode("environments"));
    databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    typeHandlerElement(root.evalNode("typeHandlers"));
    mapperElement(root.evalNode("mappers"));
  } catch (Exception e) {
    throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
  }
}
由parseCOnfiguration方法咱們能夠看到,configuraction加載了這些節點進行配置: :propertiestypeAliasespluginsobjectFactoryobjectWrapperFactorysettingsenvironmentsdatabaseIdProvidertypeHandlersmappers
下列是配置說明:一下配置屬性你均可以在中官方文檔找到: http://www.mybatis.org/mybatis-3/zh
Properties:屬性配置
 
<properties resource="org/mybatis/example/config.properties">//這是第一種
//第二種:
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>
//第三種:
屬性也能夠被傳遞到 SqlSessionFactoryBuilder.build()方法中
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
// ... or ...
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);
//引用屬性配置
<dataSource type="POOLED">//
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>
 

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

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

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

 

Settings:設置

 

 

<settings>
  <setting name="cacheEnabled" value="true"/>//全局地開啓或關閉配置文件中的全部映射器已經配置的任何緩存。
  <setting name="lazyLoadingEnabled" value="true"/>//延遲加載的全局開關。當開啓時,全部關聯對象都會延遲加載。 特定關聯關係中可經過設置fetchType屬性來覆蓋該項的開關狀態。
  <setting name="multipleResultSetsEnabled" value="true"/>//是否容許單一語句返回多結果集(須要兼容驅動)。
  <setting name="useColumnLabel" value="true"/>//使用列標籤代替列名。不一樣的驅動在這方面會有不一樣的表現, 具體可參考相關驅動文檔或經過測試這兩種不一樣的模式來觀察所用驅動的結果。
  <setting name="useGeneratedKeys" value="false"/>容許 JDBC 支持自動生成主鍵,須要驅動兼容。 若是設置爲 true 則這個設置強制使用自動生成主鍵,儘管一些驅動不能兼容但仍可正常工做(好比 Derby)。
  <setting name="autoMappingBehavior" value="PARTIAL"/>指定 MyBatis 應如何自動映射列到字段或屬性。 NONE 表示取消自動映射;PARTIAL 只會自動映射沒有定義嵌套結果集映射的結果集。 FULL 會自動映射任意複雜的結果集(不管是否嵌套)。
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
          @指定發現自動映射目標未知列(或者未知屬性類型)的行爲。
                    NONE: 不作任何反應
                    WARNING: 輸出提醒日誌 ('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior'的日誌等級必須設置爲 WARN)
                    FAILING: 映射失敗 (拋出 SqlSessionException)
 
  <setting name="defaultExecutorType" value="SIMPLE"/>配置默認的執行器。SIMPLE 就是普通的執行器;REUSE 執行器會重用預處理語句(prepared statements); BATCH 執行器將重用語句並執行批量更新。
  <setting name="defaultStatementTimeout" value="25"/>設置超時時間,它決定驅動等待數據庫響應的秒數。
  <setting name="defaultFetchSize" value="100"/>爲驅動的結果集獲取數量(fetchSize)設置一個提示值。此參數只能夠在查詢設置中被覆蓋
  <setting name="safeRowBoundsEnabled" value="false"/>容許在嵌套語句中使用分頁(RowBounds)。若是容許使用則設置爲false
  <setting name="mapUnderscoreToCamelCase" value="false"/>是否開啓自動駝峯命名規則(camel case)映射,即從經典數據庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的相似映射。
  <setting name="localCacheScope" value="SESSION"/>MyBatis 利用本地緩存機制(Local Cache)防止循環引用(circular references)和加速重複嵌套查詢。 默認值爲 SESSION,這種狀況下會緩存一個會話中執行的全部查詢。 若設置值爲 STATEMENT,本地會話僅用在語句執行上,對相同 SqlSession 的不一樣調用將不會共享數據。
  <setting name="jdbcTypeForNull" value="OTHER"/>當沒有爲參數提供特定的 JDBC 類型時,爲空值指定 JDBC 類型。 某些驅動須要指定列的 JDBC 類型,多數狀況直接用通常類型便可,好比 NULL、VARCHAR 或 OTHER。
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>指定哪一個對象的方法觸發一次延遲加載。
</settings>
 

@typeAliases:類型別名

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

第一種:

<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>
別名不區分大小寫.

第二種:

也能夠指定包名,掃描包西面的全部類並根據類名配置別名:
<typeAliases>
  <package name="domain.blog"/>
</typeAliases>
每個在包 domain.blog 中的 Java Bean,在沒有註解的狀況下,會使用 Bean 的首字母小寫的非限定類名來做爲它的別名。如有註解,則別名爲其註解值
@Alias("author")
public class Author {…}

還有一些 Java 類型內建的相應的類型別名緩存

別名服務器

映射的類型session

_bytemybatis

byte併發

_longapp

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

 

plugins:插件,其實就是攔截器

MyBatis 容許你在已映射語句執行過程當中的某一點進行攔截調用。默認狀況下,MyBatis 容許使用插件來攔截的方法調用包括:
  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)//  Executor 是負責執行低層映射語句的內部對象,真正執行sql的對象
  • ParameterHandler (getParameterObject, setParameters)//參數映射器,處理參數的
  • ResultSetHandler (handleResultSets, handleOutputParameters)//結果集映射器,處理返回結果的
  • StatementHandler (prepare, parameterize, batch, update, query)//StatementID映射器
    • environment 環境變量
      • transactionManager 事務管理器
      • dataSource 數據源
 

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 方法。

objectWrapperFactory:對象包裝工廠

reflectoryFactory:

environments:環境呢

開發、測試和生產環境須要有不一樣的配置;或者共享相同 Schema 的多個生產數據庫, 想使用相同的 SQL 映射。許多相似的用例。若是你有這種需求既能夠配置多個環境變量

<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 要匹配其中一個環境 ID。

事務管理器(transactionManager)

添加事務管理

  • JDBC – 這個配置就是直接使用了 JDBC 的提交和回滾設置,它依賴於從數據源獲得的鏈接來管理事務做用域。
  • MANAGED – 這個配置幾乎沒作什麼。它歷來不提交或回滾一個鏈接,而是讓容器來管理事務的整個生命週期(好比 JEE 應用服務器的上下文)。 默認狀況下它會關閉鏈接,然而一些容器並不但願這樣,所以須要將 closeConnection 屬性設置爲 false 來阻止它默認的關閉行爲。例如:
<transactionManager type="MANAGED">
  <property name="closeConnection" value="false"/>
</transactionManager>
提示若是你正在使用 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– 這個數據源的實現只是每次被請求時打開和關閉鏈接。雖然有點慢,但對於在數據庫鏈接可用性方面沒有過高要求的簡單應用程序來講,是一個很好的選擇。 不一樣的數據庫在性能方面的表現也是不同的,對於某些數據庫來講,使用鏈接池並不重要,這個配置就很適合這種情形。UNPOOLED 類型的數據源僅僅須要配置如下 5 種屬性:

  • driver – 這是 JDBC 驅動的 Java 類的徹底限定名(並非 JDBC 驅動中可能包含的數據源類)。
  • url – 這是數據庫的 JDBC URL 地址。
  • username – 登陸數據庫的用戶名。
  • password – 登陸數據庫的密碼。
  • defaultTransactionIsolationLevel – 默認的鏈接事務隔離級別。

做爲可選項,你也能夠傳遞屬性給數據庫驅動。要這樣作,屬性的前綴爲「driver.」,例如:

  • driver.encoding=UTF8

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

POOLED

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

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

  • poolMaximumActiveConnections – 在任意時間能夠存在的活動(也就是正在使用)鏈接數量,默認值:10
  • poolMaximumIdleConnections – 任意時間可能存在的空閒鏈接數。
  • poolMaximumCheckoutTime – 在被強制返回以前,池中鏈接被檢出(checked out)時間,默認值:20000 毫秒(即 20 秒)
  • poolTimeToWait – 這是一個底層設置,若是獲取鏈接花費了至關長的時間,鏈接池會打印狀態日誌並從新嘗試獲取一個鏈接(避免在誤配置的狀況下一直安靜的失敗),默認值:20000 毫秒(即 20 秒)。
  • poolMaximumLocalBadConnectionTolerance – 這是一個關於壞鏈接容忍度的底層設置, 做用於每個嘗試從緩存池獲取鏈接的線程. 若是這個線程獲取到的是一個壞的鏈接,那麼這個數據源容許這個線程嘗試從新獲取一個新的鏈接,可是這個從新嘗試的次數不該該超過 poolMaximumIdleConnections 與 poolMaximumLocalBadConnectionTolerance 之和。 默認值:3 (新增於 3.4.5)
  • poolPingQuery – 發送到數據庫的偵測查詢,用來檢驗鏈接是否正常工做並準備接受請求。默認是「NO PING QUERY SET」,這會致使多數數據庫驅動失敗時帶有一個恰當的錯誤消息。
  • poolPingEnabled – 是否啓用偵測查詢。若開啓,須要設置 poolPingQuery 屬性爲一個可執行的 SQL 語句(最好是一個速度很是快的 SQL 語句),默認值:false。
  • poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的頻率。能夠被設置爲和數據庫鏈接超時時間同樣,來避免沒必要要的偵測,默認值:0(即全部鏈接每一時刻都被偵測 — 固然僅當 poolPingEnabled 爲 true 時適用)。

JNDI 

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>

 

databasesIDProvider: 數據庫廠商標識.

爲了解決數據庫廠商不一樣的而形成的語句不能執行問題.

typeHandlers:類型處理器

不管是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,仍是從結果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型。
提示 從 3.4.5 開始,MyBatis 默認支持 JSR-310(日期和時間 API) 。

默認的類型處理器

類型處理器

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 類型,存儲枚舉的索引(而不是名稱)。

InstantTypeHandler

java.time.Instant

TIMESTAMP

LocalDateTimeTypeHandler

java.time.LocalDateTime

TIMESTAMP

LocalDateTypeHandler

java.time.LocalDate

DATE

LocalTimeTypeHandler

java.time.LocalTime

TIME

OffsetDateTimeTypeHandler

java.time.OffsetDateTime

TIMESTAMP

OffsetTimeTypeHandler

java.time.OffsetTime

TIME

ZonedDateTimeTypeHandler

java.time.ZonedDateTime

TIMESTAMP

YearTypeHandler

java.time.Year

INTEGER

MonthTypeHandler

java.time.Month

INTEGER

YearMonthTypeHandler

java.time.YearMonth

VARCHAR or LONGVARCHAR

JapaneseDateTypeHandler

java.time.chrono.JapaneseDate

DATE

自定義類型處理器

你能夠重寫類型處理器或建立你本身的類型處理器來處理不支持的或非標準的類型。

 具體作法爲:實現 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 直到語句被執行才清楚數據類型。

使用這個的類型處理器將會覆蓋已經存在的處理 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 屬性中也同時指定,則註解方式將被忽略。

當決定在ResultMap中使用某一TypeHandler時,此時java類型是已知的(從結果類型中得到),可是JDBC類型是未知的。 所以Mybatis使用javaType=[TheJavaType], jdbcType=null的組合來選擇一個TypeHandler。 這意味着使用@MappedJdbcTypes註解能夠限制TypeHandler的範圍,同時除非顯式的設置,不然TypeHandler在ResultMap中將是無效的。 若是但願在ResultMap中使用TypeHandler,那麼設置@MappedJdbcTypes註解的includeNullJdbcType=true便可。 然而從Mybatis 3.4.0開始,若是只有一個註冊的TypeHandler來處理Java類型,那麼它將是ResultMap使用Java類型時的默認值(即便沒有includeNullJdbcType=true)。

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

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

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

你能夠建立一個可以處理多個類的泛型類型處理器。爲了使用泛型類型處理器, 須要增長一個接受該類的 class 做爲參數的構造器,這樣在構造一個類型處理器的時候 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

 

@mappers:映射器

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

映射mapper文件

 

第一種: 使用相對於類路徑的資源引用

<!-- 使用相對於類路徑的資源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

第二種: 使用徹底限定資源定位符(URL)

<!-- 使用徹底限定資源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

第三種: 使用映射器接口實現類的徹底限定類名

<!-- 使用映射器接口實現類的徹底限定類名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

第四種: 使用映射器接口實現類的徹底限定類名

<!-- 將包內的映射器接口實現所有註冊爲映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>
相關文章
相關標籤/搜索