Mybatis配置之<environments>配置元素詳解
在這篇文章中,我們接著前文繼續(xù)往下看其他的配置元素,今天的主角就是我們的<environments>元素,該元素用于對(duì)我們需要訪問(wèn)的數(shù)據(jù)庫(kù)配置進(jìn)行設(shè)置,
我們先來(lái)看一下配置
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務(wù)管理 -->
<transactionManager type="JDBC" />
<!-- 數(shù)據(jù)庫(kù)連接池 -->
<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>從上面看,我們知道<environments>下面可以配置多個(gè)<environment>元素節(jié)點(diǎn),而每個(gè)<environment>節(jié)點(diǎn)我們可以配置兩個(gè)東西,一個(gè)是事務(wù)管理器配置<transactionManager>,另一個(gè)是數(shù)據(jù)源配置<dataSource>。
我們先從源碼開(kāi)始看起,看看這塊是怎么解析的,然后再具體看里面都要配置什么哪些參數(shù)。
還是從解析的入口開(kāi)始看起

進(jìn)入方法內(nèi)部

從代碼看,就是首先獲取<environments>標(biāo)簽元素的default屬性,這個(gè)屬性作用就是指定當(dāng)前情況下使用哪個(gè)數(shù)據(jù)庫(kù)配置,也就是使用哪個(gè)<environment>節(jié)點(diǎn)的配置,default的值就是配置的<environment>標(biāo)簽元素的id值。
正如上面代碼中isSpecifiedEnvironment(id)方法一樣,在遍歷所有<environment>的時(shí)候一次判斷相應(yīng)的id是否是default設(shè)置的值,如果是,則使用當(dāng)前<environment>元素進(jìn)行數(shù)據(jù)庫(kù)連接的初始化。
isSpecifiedEnvironment方法如下所示

緊接著,下面的代碼就是用設(shè)置的事務(wù)管理器和數(shù)據(jù)源構(gòu)造相應(yīng)的對(duì)象了。
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());我們首先從事務(wù)管理器的解析開(kāi)始,進(jìn)入到transactionManagerElement()方法內(nèi):
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}我們可以看到,這里其實(shí)是根據(jù)<transactionManager>這個(gè)元素的type屬性來(lái)找相應(yīng)的事務(wù)管理器的。
在Mybatis里面支持兩種配置:JDBC和MANAGED。這里根據(jù)type的設(shè)置值來(lái)返回相應(yīng)的事務(wù)管理器。我們看下,在Mybatis的Configuration類中,已經(jīng)將這兩種配置及對(duì)應(yīng)的事務(wù)管理器做了某種關(guān)聯(lián),如下所示:
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}這兩種事務(wù)管理器的區(qū)別
JDBC:這個(gè)配置就是直接使用了 JDBC 的提交和回滾設(shè)置,它依賴于從數(shù)據(jù)源得到的連接來(lái)管理事務(wù)作用域。MANAGED:這個(gè)配置幾乎沒(méi)做什么。它從來(lái)不提交或回滾一個(gè)連接,而是讓容器來(lái)管理事務(wù)的整個(gè)生命周期(比如 JEE 應(yīng)用服務(wù)器的上下文)。 默認(rèn)情況下它會(huì)關(guān)閉連接,然而一些容器并不希望這樣,因此需要將 closeConnection 屬性設(shè)置為 false 來(lái)阻止它默認(rèn)的關(guān)閉行為。
例如:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
備注:如果你正在使用 Spring + MyBatis,則沒(méi)有必要配置事務(wù)管理器, 因?yàn)?Spring 模塊會(huì)使用自帶的管理器來(lái)覆蓋前面的配置。
說(shuō)完了事務(wù)管理器,緊接著,我們來(lái)看看數(shù)據(jù)源配置。
dataSource 元素使用標(biāo)準(zhǔn)的 JDBC 數(shù)據(jù)源接口來(lái)配置 JDBC 連接對(duì)象的資源。Mybatis支持三種內(nèi)建的數(shù)據(jù)源類型,分別是UNPOOLED、POOLED和JNDI,即我們?cè)谂渲?lt;dataSource>元素的type屬性時(shí),我們可以直接支持設(shè)置這三個(gè)值。
下面分別對(duì)這三種類型做一個(gè)簡(jiǎn)單的說(shuō)明
(1)UNPOOLED
這個(gè)數(shù)據(jù)源的實(shí)現(xiàn)只是每次被請(qǐng)求時(shí)打開(kāi)和關(guān)閉連接。雖然一點(diǎn)慢,它對(duì)在及時(shí)可用連接方面沒(méi)有性能要求的簡(jiǎn)單應(yīng)用程序是一個(gè)很好的選擇。
不同的數(shù)據(jù)庫(kù)在這方面表現(xiàn)也是不一樣的,所以對(duì)某些數(shù)據(jù)庫(kù)來(lái)說(shuō)使用連接池并不重要,這個(gè)配置也是理想的。
UNPOOLED 類型的數(shù)據(jù)源僅僅需要配置以下 5 種屬性:
driver:這是 JDBC 驅(qū)動(dòng)的 Java 類的完全限定名(并不是JDBC驅(qū)動(dòng)中可能包含的數(shù)據(jù)源類)。url:這是數(shù)據(jù)庫(kù)的 JDBC URL 地址。username:登錄數(shù)據(jù)庫(kù)的用戶名。password:登錄數(shù)據(jù)庫(kù)的密碼。defaultTransactionIsolationLevel:默認(rèn)的連接事務(wù)隔離級(jí)別。
作為可選項(xiàng),你也可以傳遞屬性給數(shù)據(jù)庫(kù)驅(qū)動(dòng)。要這樣做,屬性的前綴為“driver.”,例如:driver.encoding=UTF8
這將通過(guò)DriverManager.getConnection(url,driverProperties)方法傳遞值為 UTF8 的 encoding 屬性給數(shù)據(jù)庫(kù)驅(qū)動(dòng)。
(2)POOLED
這種數(shù)據(jù)源的實(shí)現(xiàn)利用“池”的概念將 JDBC 連接對(duì)象組織起來(lái),避免了創(chuàng)建新的連接實(shí)例時(shí)所必需的初始化和認(rèn)證時(shí)間。 這是一種使得并發(fā) Web 應(yīng)用快速響應(yīng)請(qǐng)求的流行處理方式。
除了上述提到 UNPOOLED 下的屬性外,會(huì)有更多屬性用來(lái)配置 POOLED 的數(shù)據(jù)源:
poolMaximumActiveConnections:在任意時(shí)間可以存在的活動(dòng)(也就是正在使用)連接數(shù)量,默認(rèn)值:10poolMaximumIdleConnections:任意時(shí)間可能存在的空閑連接數(shù)。poolMaximumCheckoutTime:在被強(qiáng)制返回之前,池中連接被檢出(checked out)時(shí)間,默認(rèn)值:20000 毫秒(即 20 秒)poolTimeToWait:這是一個(gè)底層設(shè)置,如果獲取連接花費(fèi)的相當(dāng)長(zhǎng)的時(shí)間,它會(huì)給連接池打印狀態(tài)日志并重新嘗試獲取一個(gè)連接(避免在誤配置的情況下一直安靜的失敗),默認(rèn)值:20000 毫秒(即 20 秒)。poolPingQuery:發(fā)送到數(shù)據(jù)庫(kù)的偵測(cè)查詢,用來(lái)檢驗(yàn)連接是否處在正常工作秩序中并準(zhǔn)備接受請(qǐng)求。默認(rèn)是“NO PING QUERY SET”,這會(huì)導(dǎo)致多數(shù)數(shù)據(jù)庫(kù)驅(qū)動(dòng)失敗時(shí)帶有一個(gè)恰當(dāng)?shù)腻e(cuò)誤消息。poolPingEnabled:是否啟用偵測(cè)查詢。若開(kāi)啟,也必須使用一個(gè)可執(zhí)行的 SQL 語(yǔ)句設(shè)置 poolPingQuery 屬性(最好是一個(gè)非??斓?SQL),默認(rèn)值:false。poolPingConnectionsNotUsedFor : 配置 poolPingQuery 的使用頻度。這可以被設(shè)置成匹配具體的數(shù)據(jù)庫(kù)連接超時(shí)時(shí)間,來(lái)避免不必要的偵測(cè),默認(rèn)值:0(即所有連接每一時(shí)刻都被偵測(cè) — 當(dāng)然僅當(dāng) poolPingEnabled 為 true 時(shí)適用)。
(3)JNDI
這個(gè)數(shù)據(jù)源的實(shí)現(xiàn)是為了能在如 EJB 或應(yīng)用服務(wù)器這類容器中使用,容器可以集中或在外部配置數(shù)據(jù)源,然后放置一個(gè) JNDI 上下文的引用。
這種數(shù)據(jù)源配置只需要兩個(gè)屬性:
initial_context:這個(gè)屬性用來(lái)在 InitialContext 中尋找上下文(即,initialContext.lookup(initial_context))。這是個(gè)可選屬性,如果忽略,那么 data_source 屬性將會(huì)直接從 InitialContext 中尋找。data_source:這是引用數(shù)據(jù)源實(shí)例位置的上下文的路徑。提供了 initial_context 配置時(shí)會(huì)在其返回的上下文中進(jìn)行查找,沒(méi)有提供時(shí)則直接在 InitialContext 中查找。
和其他數(shù)據(jù)源配置類似,可以通過(guò)添加前綴“env.”直接把屬性傳遞給初始上下文。比如:env.encoding=UTF8
這就會(huì)在初始上下文(InitialContext)實(shí)例化時(shí)往它的構(gòu)造方法傳遞值為 UTF8 的 encoding 屬性。
至此,關(guān)于<environments>元素的相關(guān)配置使用便介紹完畢了。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot配置resilience4j全過(guò)程
這篇文章主要介紹了springboot配置resilience4j全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
springboot 事件監(jiān)聽(tīng)的實(shí)現(xiàn)方法
這篇文章主要介紹了springboot 事件監(jiān)聽(tīng)的實(shí)現(xiàn)方法,并詳細(xì)的介紹了四種監(jiān)聽(tīng)方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04
Netty分布式pipeline管道傳播outBound事件源碼解析
這篇文章主要介紹了Netty分布式pipeline管道傳播outBound事件源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
Eclipse 導(dǎo)出可執(zhí)行Java工程/可執(zhí)行Jar文件(包含第三方Jar包)
這篇文章主要介紹了Eclipse 導(dǎo)出可執(zhí)行Java工程/可執(zhí)行Jar文件(包含第三方Jar包)的相關(guān)資料,需要的朋友可以參考下2016-11-11
用Java程序判斷是否是閏年的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇用Java程序判斷是否是閏年的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06
Java去重排序之Comparable與Comparator的使用及說(shuō)明
這篇文章主要介紹了Java去重排序之Comparable與Comparator的使用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
springboot3集成mybatis-plus報(bào)sqlSession異常的問(wèn)題解決
springboot3已經(jīng)發(fā)布正式版,但是在集成mybatis-plus最新版3.5.2的時(shí)候發(fā)現(xiàn)提示異常,本文就來(lái)介紹一下報(bào)sqlSession異常的問(wèn)題解決,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02

