mybatis全配置理解
本文只論mybatis本身,不涉及與spring整合,文中探討了mybatis最新版本提供的全部配置項的作用。
首先要了解都有哪些配置項,mybatis的SqlSession來自SqlSessionFactory,SqlSessionFactory來自SqlSessionFactoryBuilder,從SqlSessionFactoryBuilder切入分析
... public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } ...
構造SqlSessionFactoryBuilder用到了XMLConfigBuilder,然後看XMLConfigBuilder
public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; } 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); } } private void settingsElement(Properties props) throws Exception { configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL"))); configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE"))); configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true)); configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory"))); configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false)); configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false)); configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true)); configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true)); configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false)); configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE"))); configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null)); configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null)); configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false)); configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false)); configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION"))); configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER"))); configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString")); configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true)); configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage"))); @SuppressWarnings("unchecked") Class<? extends TypeHandler> typeHandler = (Class<? extends TypeHandler>)resolveClass(props.getProperty("defaultEnumTypeHandler")); configuration.setDefaultEnumTypeHandler(typeHandler); configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false)); configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true)); configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false)); configuration.setLogPrefix(props.getProperty("logPrefix")); @SuppressWarnings("unchecked") Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl")); configuration.setLogImpl(logImpl); configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory"))); }
configuration節點為根節點。
可以配置10個子節點:properties、settings、typeAliases、plugins、objectFactory、objectWrapperFactory、environments、databaseIdProvider、typeHandlers、mappers。
-
properties
這些屬性都是可外部配置且可動態替換的,既可以在典型的 Java 屬性檔案中配置,亦可通過 properties 元素的子元素來傳遞。例如:
<!-- mybatis-config.xml --> <properties resource="jdbc.properties"></properties> <!-- mybatis-config.xml --> <properties> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/a"/> <property name="username" value="root"/> <property name="password" value="root"/> </properties>settings
-
settings
這是 MyBatis 中極為重要的調整設定,它們會改變 MyBatis 的執行時行為。
<!-- mybatis-config.xml --> <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>
引數介紹如下:
引數
官方中文描述
理解
可選值
預設值
cacheEnabled
全域性地開啟或關閉配置檔案中的所有對映器已經配置的任何快取。
mybatis快取,不支援叢集環境,必須設定成false。
true | false
true
lazyLoadingEnabled
延遲載入的全域性開關。當開啟時,所有關聯物件都會延遲載入。 特定關聯關係中可通過設定fetchType屬性來覆蓋該項的開關狀態
首先要理解懶載入:簡單例子
public class Order { public Long id; public Long addressId; public Address address; }
public class Address { public Long id; public String name; }
<!-- addressMapper.xml --> <mapper namespace="addressMapperSpace"> <select id="getAddressById" parameterType="Long" resultType="Address"> select id,name from t_address where id = #{id} </select> </mapper>
<!-- orderMapper.xml --> <mapper namespace="..."> <resultMap id="orderMap" type="Order"> <id property="id" column="id" /> <association property="address" column="address_id" select="addressMapperSpace.getAddressById" /> </resultMap> <select id="getOrderById" resultMap="orderMap" parameterType="Long"> select id,address_id from t_order where id = #{id} <select> </mapper>
如果是懶載入,那麼訪問order的address屬性時才會去查詢address。
可以不設定
true | false
false
aggressiveLazyLoading
當開啟時,任何方法的呼叫都會載入該物件的所有屬性。否則,每個屬性會按需載入(參考lazyLoadTriggerMethods).
當設定為true時,懶載入的物件可能被任何懶屬性全部載入;否則,每個屬性按需載入。一般不用。
可以不設定
true | false
false (true in ≤3.4.1)
lazyLoadTriggerMethods
指定物件的哪個方法觸發一次延遲載入。
在lazyLoadingEnabled=true時有效,呼叫本方法會使得所有延遲載入屬性被載入,如果有多個懶載入屬性,可以使用這個方法把所有懶載入屬性一起載入了。
可以不設定
用逗號分隔的方法列表。
equals,clone,hashCode,toString
proxyFactory
指定 Mybatis 建立具有延遲載入能力的物件所用到的代理工具。
mybatis延遲載入用的工具,舊版本使用的是CGLIB動態代理技術,新版本支援使用JAVASSIST(Javassist是一個執行時編譯庫,他能動態的生成或修改類的位元組碼)來完成。
可以不設定
CGLIB | JAVASSIST
JAVASSIST (MyBatis 3.3 or above)
multipleResultSetsEnabled
是否允許單一語句返回多結果集(需要相容驅動)。
sql與ResultSet一對多的用法, 沒找到用法。
可以不設定
true | false
true
useColumnLabel
使用列標籤代替列名。不同的驅動在這方面會有不同的表現, 具體可參考相關驅動文件或通過測試這兩種不同的模式來觀察所用驅動的結果。
在Select欄位的時候使用AS,用得上,由於預設true。
可以不設定
true | false
true
useGeneratedKeys
允許 JDBC 支援自動生成主鍵,需要驅動相容。 如果設定為 true 則這個設定強制使用自動生成主鍵,儘管一些驅動不能相容但仍可正常工作(比如 Derby)。
我們使用mysql資料庫自增主鍵,在xml的insert塊中如果使用useGeneratedKeys來獲得生成的主鍵,那這個屬性必須設定成true。如果使用以下方法,那也可以不設定。
<insert ...> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
SELECT LAST_INSERT_ID() </selectKey> ... </insert>
true | false
false
autoMappingBehavior
指定 MyBatis 應如何自動對映列到欄位或屬性。 NONE 表示取消自動對映;PARTIAL 只會自動對映沒有定義巢狀結果集對映的結果集。 FULL 會自動對映任意複雜的結果集(無論是否巢狀)。
如果修改成FULL,會由於沒及時更新model導致對映失敗。
<resultMap id="BaseResultMap" type="com.meituan.shangou.order.center.domain.PoiConfig"> <id column="id" jdbcType="BIGINT" property="id" /> <result column="poi_id" jdbcType="BIGINT" property="poiId" /> <result column="part_aftersale_show" jdbcType="BIT" property="partAftersaleShow" /> </resultMap>
可以不設定
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", 在執行dao.save()時,就相當於JDBC的stmt.execute(sql);
-
設為"REUSE", 在執行dao.save()時,相當於JDBC重用一條sql,再通過stmt傳入多項引數值,然後執行stmt.executeUpdate()或stmt.executeBatch();重用sql的場景不太常見,因此用SIMPLE就可以了。
-
設為"BATCH", 在執行dao.save()時,相當於JDBC語句的 stmt.addBatch(sql),即僅僅是將執行SQL加入到批量計劃。 所以此時不會丟擲主鍵衝突等執行時異常,而只有臨近commit前執行stmt.execteBatch()後才會丟擲異常。
可以不設定
SIMPLE REUSE BATCH
SIMPLE
defaultStatementTimeout
設定超時時間,它決定驅動等待資料庫響應的秒數。
這是以秒為單位的全域性sql超時時間設定,當超出了設定的超時時間時,會丟擲SQLTimeoutException。建議設定一個合理值。
任意正整數
Not Set (null)
defaultFetchSize
為驅動的結果集獲取數量(fetchSize)設定一個提示值。此引數只可以在查詢設定中被覆蓋。
mysql不支援fetchSize。
一般使用分頁外掛即可。
可以不設定
任意正整數
Not Set (null)
safeRowBoundsEnabled
允許在巢狀語句中使用分頁(RowBounds)。如果允許使用則設定為false。
使用場景:session.select("...", null, new RowBounds(1, 2),resultHandler);
一般使用分頁外掛即可。
可以不設定
true | false
false
safeResultHandlerEnabled
允許在巢狀語句中使用分頁(ResultHandler)。如果允許使用則設定為false。
使用場景:session.select("...", null, new RowBounds(1, 2),resultHandler);
一般使用分頁外掛即可。
可以不設定
true | false
true
mapUnderscoreToCamelCase
是否開啟自動駝峰命名規則(camel case)對映,即從經典資料庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的類似對映。
駝峰命名對映,手寫mapper不去寫resultMap時推薦開啟。使用mybatis-generator時,不開啟也ok。
true | false
false
localCacheScope
MyBatis 利用本地快取機制(Local Cache)防止迴圈引用(circular references)和加速重複巢狀查詢。 預設值為 SESSION,這種情況下會快取一個會話中執行的所有查詢。 若設定值為 STATEMENT,本地會話僅用在語句執行上,對相同 SqlSession 的不同調用將不會共享資料。
mybatis快取,不支援叢集環境,這個就不用管了。
可以不設定
SESSION | STATEMENT
SESSION
jdbcTypeForNull
當沒有為引數提供特定的 JDBC 型別時,為空值指定 JDBC 型別。 某些驅動需要指定列的 JDBC 型別,多數情況直接用一般型別即可,比如 NULL、VARCHAR 或 OTHER。
正常情況下我們都配了。
可以不設定
JdbcType 常量. 大多都為: NULL, VARCHAR and OTHER
OTHER (java.lang.Object)
defaultScriptingLanguage
指定動態 SQL 生成的預設語言。
雖然官方名稱叫做LanguageDriver,其實叫做解析器可能更加合理。MyBatis 從 3.2 開始支援可插拔的指令碼語言,因此你可以在插入一種語言的驅動(language driver)之後來寫基於這種語言的動態 SQL 查詢比如mybatis除了XML格式外,還提供了mybatis-velocity,允許使用velocity表示式編寫SQL語句。可以通過實現LanguageDriver介面的方式來插入一種語言。
可以不設定
一個類型別名或完全限定類名。
org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
defaultEnumTypeHandler
指定 Enum 使用的預設 TypeHandler 。 (從3.4.5開始)
預設的EnumTypeHandler存入資料庫的是列舉的name,
mybatis還提供了EnumOrdinalTypeHandler存入資料庫的是列舉的位置。
這倆都不太好用,如果想要把資料庫查詢結果與列舉自動轉換,可以自定義typeHandler來實現。在查詢或操作資料時以列舉傳輸優勢並不大,只提供對應的列舉也可滿足需求。
可以不設定
一個類型別名或完全限定類名。
org.apache.ibatis.type.EnumTypeHandler
callSettersOnNulls
指定當結果集中值為 null 的時候是否呼叫對映物件的 setter(map 物件時為 put)方法,這對於有 Map.keySet() 依賴或 null 值初始化的時候是有用的。注意基本型別(int、boolean等)是不能設定成 null 的。
假設將資料從DB中查詢出來如果將欄位對映為Map,而不想封裝成Bean。預設情況下,Mybatis對Map的解析生成, 如果值(value)為null的話,那麼key也不會被加入到map中.
於是對Map遍歷時,key就遍歷不到。部分情況會有需要key存在,value=null的情況,依據多數實際場景來看,使用預設值false沒問題。
可以不設定
true | false
false
returnInstanceForEmptyRow
當返回行的所有列都是空時,MyBatis預設返回null。 當開啟這個設定時,MyBatis會返回一個空例項。 請注意,它也適用於巢狀的結果集 (i.e. collectioin and association)。(從3.4.2開始)
查詢結果沒有的時候,返回null是合理的,返回一個空物件容易硬氣誤會。
不要設定
true | false
false
logPrefix
指定 MyBatis 增加到日誌名稱的字首。
日誌字首,要不要看個人喜好。
可以不設定
任何字串
Not set
logImpl
指定 MyBatis 所用日誌的具體實現,未指定時將自動查詢。
不要設定
SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
Not set
vfsImpl
指定VFS的實現
VFS主要用來載入容器內的各種資源,比如jar或者class檔案。mybatis提供了2個實現 JBoss6VFS 和 DefaultVFS,並提供了使用者擴充套件點,用於自定義VFS實現,載入順序是自定義VFS實現 > 預設VFS實現 取第一個載入成功的,預設情況下會先載入JBoss6VFS,如果classpath下找不到jboss的vfs實現才會載入預設VFS實現。
可以不設定
自定義VFS的實現的類全限定名,以逗號分隔。
Not set
useActualParamName
允許使用方法簽名中的名稱作為語句引數名稱。 為了使用該特性,你的工程必須採用Java 8編譯,並且加上-parameters選項。(從3.4.1開始)
mybatis的全域性配置useActualParamName決定了mapper中引數的寫法,預設為true。此時無需再使用@Param。
Order getOrderByCondition (Long id,Long addressId)
<select id="getOrderByCondition" resultType="Order" > select * from t_order where id = #{id} and addressId = #{addressId} </select>
如果是false那麼可寫成
<select id="getOrderByCondition" resultType="Order" > select * from t_order where id = #{0} and addressId = #{1} </select>
使用這個特性必須在jdk1.8場景。這是因為:在Java 8之前的版本,程式碼編譯為class檔案後,方法引數的型別是固定的,但引數名稱卻丟失了,這和動態語言嚴重依賴引數名稱形成了鮮明對比。現在,Java 8開始在class檔案中保留引數名,給反射帶來了極大的便利。jdk8增加了類Parameter。
可以不設定
true | false
true
configurationFactory
指定一個提供Configuration例項的類。 這個被返回的Configuration例項用來載入被反序列化物件的懶載入屬性值。 這個類必須包含一個簽名方法static Configuration getConfiguration(). (從 3.2.3 版本開始)
此時mybatis全域性的Configuration將被開發者手動指定。
建議不設定
類型別名或者全類名.
Not set
-
-
typeAliases
類型別名是為 Java 型別設定一個短的名字。它只和 XML 配置有關,原理是用hashMap關聯,存在的意義僅在於用來減少類完全限定名的冗餘。例如:
<!-- mybatis-config.xml --> <typeAliases> <typeAlias alias="OrderMain" type="order.center.domain.OrderMain"/> </typeAliases> <!-- mybatis-config.xml --> <typeAliases> <package name="order.center.domain"/> </typeAliases>
-
typeHandlers
無論是 MyBatis 在預處理語句(PreparedStatement)中設定一個引數時,還是從結果集中取出一個值時, 都會用型別處理器將獲取的值以合適的方式轉換成 Java 型別。
可以重寫型別處理器或建立你自己的型別處理器來處理不支援的或非標準的型別。 具體做法為:實現 org.apache.ibatis.type.TypeHandler 介面, 或繼承一個很便利的類 org.apache.ibatis.type.BaseTypeHandler, 然後可以選擇性地將它對映到一個 JDBC 型別。
下面是一個處理javaType=com.alibaba.fastjson.JSON時的例子
public class ExampleTypeHandler extends BaseTypeHandler<JSON> { @Override public void setNonNullParameter(PreparedStatement ps, int i, JSON parameter, JdbcType jdbcType) throws SQLException { ps.setString(i,parameter.toJSONString()); } @Override public JSON getNullableResult(ResultSet rs, String columnName) throws SQLException { return JSON.parseObject(rs.getString(columnName)); } @Override public JSON getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return JSON.parseObject(rs.getString(columnIndex)); } @Override public JSON getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return JSON.parseObject(cs.getString(columnIndex)); } }
<!-- mybatis-config.xml --> <typeHandlers> <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/> </typeHandlers>
<!-- Ordermapper.xml中使用 --> <result column="order_json" typeHandler="org.mybatis.example.ExampleTypeHandle" jdbcType="VARCHAR" property="orderJson" />
-
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,如果需要使用的話,建議是在物件建立時需要做一些操作,或前或後,用於改變或者豐富被建立物件。
-
objectWrapperFactory
最新的官方文件中已經去掉了這個配置項。原用來提供自定義的ObjectWrapper
-
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 介面,並指定想要攔截的方法簽名即可。
例如配置pageHelper:
<!-- mybatis-config.xml --> <plugins> <plugin interceptor="com.github.pagehelper.PageHelper"> <property name="dialect" value="mysql"/> <property name="offsetAsPageNum" value="false"/> <property name="rowBoundsWithCount" value="false"/> <property name="pageSizeZero" value="true"/> <property name="reasonable" value="false"/> <property name="supportMethodsArguments" value="false"/> <property name="returnPageInfo" value="none"/> </plugin> </plugins>
-
-
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);
環境元素定義瞭如何配置環境。
<!-- mybatis-config.xml --> <environments default="development"> <environment id="development"> <!--Mybatis管理事務是分為兩種方式: (1)使用JDBC的事務管理機制,就是利用java.sql.Connection物件完成對事務的提交 (2)使用MANAGED的事務管理機制,這種機制mybatis自身不會去實現事務管理,而是讓程式的容器(JBOSS,WebLogic)來實現對事務的管理 --> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 可以直接用properties也可以在這配 --> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> <environment id="test"> <!-- mybatis提供的區分不同環境的資料庫連線配置 --> </environment> </environments>
-
-
databaseIdProvider
MyBatis 可以根據不同的資料庫廠商執行不同的語句,這種多廠商的支援是基於對映語句中的 databaseId 屬性。 MyBatis 會載入不帶 databaseId 屬性和帶有匹配當前資料庫 databaseId 屬性的所有語句。 如果同時找到帶有 databaseId 和不帶 databaseId 的相同語句,則後者會被捨棄。 為支援多廠商特性只要像下面這樣在 mybatis-config.xml 檔案中加入 databaseIdProvider 即可:
我們實際使用中,不同資料庫大概率是不同資料來源,很低概率出現同一個mapper兩種資料庫使用,因此這個配置項幾乎不可能用上。
<!-- mybatis-config.xml --> <databaseIdProvider type="DB_VENDOR"> <property name="SQL Server" value="sqlserver"/> <property name="DB2" value="db2"/> <property name="Oracle" value="oracle" /> <property name="Mysql" value="mysql" /> </databaseIdProvider>
<!-- mapper.xml --> <insert id="insertTest" ...> INSERT INTO users(name, age) VALUES('zhangsan', 1), ('wangwu', 2), ('zhaoliu', 3); </insert> <insert id="insertTest" ... databaseId="oracle"> INSERT ALL INTO users VALUES('zhangsan', 1) INTO usersVALUES ('wangwu', 2) INTO usersVALUES ('zhaoliu', 3); </insert>
-
mappers
既然 MyBatis 的行為已經由上述元素配置完了,我們現在就要定義 SQL 對映語句了。但是首先我們需要告訴 MyBatis 到哪裡去找到這些語句。 Java 在自動查詢這方面沒有提供一個很好的方法,所以最佳的方式是告訴 MyBatis 到哪裡去找對映檔案。你可以使用相對於類路徑的資源引用, 或完全限定資源定位符(包括 file:/// 的 URL),或類名和包名等。例如:
<!-- mybatis-config.xml 使用spring後可以在sqlSessionFactory裡配置*.xml--> <mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers>
<!-- mybatis-config.xml 此方法mapper介面和xml必須同名放在一起--> <mappers> <package name="org.mybatis.builder"/> </mappers>
<!-- mybatis-config.xml 絕對路徑,不可用--> <mappers> <mapper url="file:///var/mappers/AuthorMapper.xml"/> <mapper url="file:///var/mappers/BlogMapper.xml"/> <mapper url="file:///var/mappers/PostMapper.xml"/> </mappers>