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>

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

<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 文件中對應的值來替換。這樣就爲配置提供了諸多靈活選擇。數據庫

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

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props); // ... or ... SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);

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

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

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

  從MyBatis 3.4.2開始,你能夠爲佔位符指定一個默認值。例如:        session

<dataSource type="POOLED"> <!-- ... --> <property name="username" value="${username:ut_user}"/> <!-- If 'username' property not present, username become 'ut_user' --> </dataSource>

這個特性默認是關閉的。若是你想爲佔位符指定一個默認值,   你應該添加一個指定的屬性來開啓這個特性。例如:        mybatis

<properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- Enable this feature --> </properties>

提示 你可使用 ":" 做爲屬性鍵(e.g. db:username)           或者你也能夠在sql定義中使用 OGNL 表達式的三元運算符(e.g. ${tableName != null ? tableName : 'global_constants'}),   你應該經過增長一個指定的屬性來改變分隔鍵和默認值的字符。例如:         併發

<properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- Change default value of separator --> </properties>
<dataSource type="POOLED"> <!-- ... --> <property name="username" value="${db:username?:ut_user}"/> </dataSource>

settings

這是 MyBatis 中極爲重要的調整設置,它們會改變 MyBatis 的運行時行爲。下表描述了設置中各項的意圖、默認值等。

設置參數 描述 有效值 默認值
                cacheEnabled               全局地開啓或關閉配置文件中的全部映射器已經配置的任何緩存。               true | false                               true              
                lazyLoadingEnabled               延遲加載的全局開關。當開啓時,全部關聯對象都會延遲加載。                特定關聯關係中可經過設置fetchType屬性來覆蓋該項的開關狀態。               true | false                               false              
                aggressiveLazyLoading               當開啓時,任何方法的調用都會加載該對象的全部屬性。不然,每一個屬性會按需加載(參考lazyLoadTriggerMethods).                               true | false                               false (true in ≤3.4.1)              
                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               指定發現自動映射目標未知列(或者未知屬性類型)的行爲。                
  • NONE: 不作任何反應
  • WARNING: 輸出提醒日誌 ('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日誌等級必須設置爲 WARN)
  • FAILING: 映射失敗 (拋出 SqlSessionException)
                NONE, WARNING, FAILING                               NONE              
                defaultExecutorType               配置默認的執行器。SIMPLE 就是普通的執行器;REUSE 執行器會重用預處理語句(prepared statements);                 BATCH 執行器將重用語句並執行批量更新。               SIMPLE                REUSE                BATCH                               SIMPLE              
                defaultStatementTimeout               設置超時時間,它決定驅動等待數據庫響應的秒數。                               任意正整數               Not Set (null)              
                defaultFetchSize               爲驅動的結果集獲取數量(fetchSize)設置一個提示值。此參數只能夠在查詢設置中被覆蓋。                               任意正整數               Not Set (null)              
                safeRowBoundsEnabled               容許在嵌套語句中使用分頁(RowBounds)。若是容許使用則設置爲false。               true | false                               False              
                safeResultHandlerEnabled               容許在嵌套語句中使用分頁(ResultHandler)。若是容許使用則設置爲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 常量. 大多都爲: NULL, VARCHAR and OTHER                               OTHER              
                lazyLoadTriggerMethods               指定哪一個對象的方法觸發一次延遲加載。                               用逗號分隔的方法列表。               equals,clone,hashCode,toString              
                defaultScriptingLanguage               指定動態 SQL 生成的默認語言。                               一個類型別名或徹底限定類名。               org.apache.ibatis.scripting.xmltags.XMLLanguageDriver              
                defaultEnumTypeHandler               指定 Enum 使用的默認 TypeHandler 。 (從3.4.5開始)               一個類型別名或徹底限定類名。               org.apache.ibatis.type.EnumTypeHandler              
                callSettersOnNulls               指定當結果集中值爲 null 的時候是否調用映射對象的 setter(map 對象時爲 put)方法,這對於有 Map.keySet() 依賴或 null 值初始化的時候是有用的。注意基本類型(int、boolean等)是不能設置成 null 的。               true | false                               false              
                returnInstanceForEmptyRow               當返回行的全部列都是空時,MyBatis默認返回null。 當開啓這個設置時,MyBatis會返回一個空實例。 請注意,它也適用於嵌套的結果集 (i.e. collectioin and association)。(從3.4.2開始)               true | false                               false              
                logPrefix               指定 MyBatis 增長到日誌名稱的前綴。                               任何字符串               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               指定VFS的實現                               自定義VFS的實現的類全限定名,以逗號分隔。               Not set              
                useActualParamName               容許使用方法簽名中的名稱做爲語句參數名稱。 爲了使用該特性,你的工程必須採用Java 8編譯,而且加上-parameters選項。(從3.4.1開始)               true | false                               true              
                configurationFactory               指定一個提供Configuration實例的類。 這個被返回的Configuration實例用來加載被反序列化對象的懶加載屬性值。 這個類必須包含一個簽名方法static Configuration getConfiguration(). (從 3.2.3 版本開始)               類型別名或者全類名.               Not set              

一個配置完整的 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 配置有關,存在的意義僅在於用來減小類徹底限定名的冗餘。例如:

<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 類型。下表描述了一些默認的類型處理器。

提示         從 3.4.5 開始,MyBatis 默認支持 JSR-310(日期和時間 API) 。        

                類型處理器               Java 類型               JDBC 類型              
BooleanTypeHandler               java.lang.Boolean, boolean               數據庫兼容的 BOOLEAN              
ByteTypeHandler               java.lang.Byte, byte               數據庫兼容的 NUMERICBYTE              
ShortTypeHandler               java.lang.Short, short               數據庫兼容的 NUMERICSHORT INTEGER              
IntegerTypeHandler               java.lang.Integer, int               數據庫兼容的 NUMERICINTEGER              
LongTypeHandler               java.lang.Long, long               數據庫兼容的 NUMERICLONG INTEGER              
FloatTypeHandler               java.lang.Float, float               數據庫兼容的 NUMERICFLOAT              
DoubleTypeHandler               java.lang.Double, double               數據庫兼容的 NUMERICDOUBLE              
BigDecimalTypeHandler               java.math.BigDecimal               數據庫兼容的 NUMERICDECIMAL              
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               任何兼容的 NUMERICDOUBLE 類型,存儲枚舉的索引(而不是名稱)。              
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 直到語句被執行才清楚數據類型。        

          經過類型處理器的泛型,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; } ...

EnumTypeHandlerEnumOrdinalTypeHandler 都是泛型類型處理器(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 是負責執行低層映射語句的內部對象。

提示           覆蓋配置類        

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

配置環境(environments)

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

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

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

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

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

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

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

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader); SqlSessionFactory factory = new 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 要匹配其中一個環境 ID。        

事務管理器(transactionManager)        

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

  • 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 類型的數據源僅僅須要配置如下 5 種屬性:

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

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

  • driver.encoding=UTF8

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

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 – 這個數據源的實現是爲了能在如 EJB 或應用服務器這類容器中使用,容器能夠集中或在外部配置數據源,而後放置一個 JNDI 上下文的引用。這種數據源配置只須要兩個屬性:        

  • initial_context – 這個屬性用來在 InitialContext 中尋找上下文(即,initialContext.lookup(initial_context))。這是個可選屬性,若是忽略,那麼 data_source 屬性將會直接從 InitialContext 中尋找。          
  • data_source – 這是引用數據源實例位置的上下文的路徑。提供了 initial_context 配置時會在其返回的上下文中進行查找,沒有提供時則直接在 InitialContext 中查找。          

和其餘數據源配置相似,能夠經過添加前綴「env.」直接把屬性傳遞給初始上下文。好比:        

  • env.encoding=UTF8

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

          你能夠經過實現接口 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>

在提供了屬性別名時,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),或類名和包名等。例如:

<!-- 使用相對於類路徑的資源引用 --> <mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers>
<!-- 使用徹底限定資源定位符(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>

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

相關文章
相關標籤/搜索