1. 程式人生 > >mybatis配置檔案conf.xml中的environment詳解

mybatis配置檔案conf.xml中的environment詳解

在這篇文章中,我們接著前文繼續往下看其他的配置元素,今天的主角就是我們的<environments>元素,該元素用於對我們需要訪問的資料庫配置進行設定,我們先來看一下配置:

  1. <environments default="development">

  2. <environment id="development">

  3. <!-- 使用jdbc事務管理 -->

  4. <transactionManager type="JDBC" />

  5. <!-- 資料庫連線池 -->

  6. <dataSource type="POOLED">

  7. <property name="driver" value="${driver}" />

  8. <property name="url" value="${url}" />

  9. <property name="username" value="${username}" />

  10. <property name="password" value="${password}" />

  11. </dataSource>

  12. </environment>

  13. </environments>


從上面看,我們知道<environments>下面可以配置多個<environment>元素節點,而每個<environment>節點我們可以配置兩個東西,一個是事務管理器配置<transactionManager>,另一個是資料來源配置<dataSource>。

我們先從原始碼開始看起,看看這塊是怎麼解析的,然後再具體看裡面都要配置什麼哪些引數。

還是從解析的入口開始看起:

進入方法內部:

從程式碼看,就是首先獲取<environments>標籤元素的default屬性,這個屬性作用就是指定當前情況下使用哪個資料庫配置,也就是使用哪個<environment>節點的配置,default的值就是配置的<environment>標籤元素的id值。

正如上面程式碼中isSpecifiedEnvironment(id)方法一樣,在遍歷所有<environment>的時候一次判斷相應的id是否是default設定的值,如果是,則使用當前<environment>元素進行資料庫連線的初始化。

isSpecifiedEnvironment方法如下所示:

緊接著,下面的程式碼就是用設定的事務管理器和資料來源構造相應的物件了。

  1. TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));

  2. DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));

  3. DataSource dataSource = dsFactory.getDataSource();

  4. Environment.Builder environmentBuilder = new Environment.Builder(id)

  5. .transactionFactory(txFactory)

  6. .dataSource(dataSource);

  7. configuration.setEnvironment(environmentBuilder.build());


我們首先從事務管理器的解析開始,進入到transactionManagerElement()方法內:

  1. private TransactionFactory transactionManagerElement(XNode context) throws Exception {

  2. if (context != null) {

  3. String type = context.getStringAttribute("type");

  4. Properties props = context.getChildrenAsProperties();

  5. TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();

  6. factory.setProperties(props);

  7. return factory;

  8. }

  9. throw new BuilderException("Environment declaration requires a TransactionFactory.");

  10. }


我們可以看到,這裡其實是根據<transactionManager>這個元素的type屬性來找相應的事務管理器的。

在Mybatis裡面支援兩種配置:JDBC和MANAGED。這裡根據type的設定值來返回相應的事務管理器。我們看下,在Mybatis的Configuration類中,已經將這兩種配置及對應的事務管理器做了某種關聯,如下所示:

  1. public Configuration() {

  2. typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);

  3. typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

  4. typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);

  5. typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);

  6. typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

  7. typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);

  8. typeAliasRegistry.registerAlias("FIFO", FifoCache.class);

  9. typeAliasRegistry.registerAlias("LRU", LruCache.class);

  10. typeAliasRegistry.registerAlias("SOFT", SoftCache.class);

  11. typeAliasRegistry.registerAlias("WEAK", WeakCache.class);

  12. typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);

  13. typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);

  14. typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

  15. typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);

  16. typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);

  17. typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);

  18. typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);

  19. typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);

  20. typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);

  21. typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

  22. typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);

  23. typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);

  24. languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);

  25. languageRegistry.register(RawLanguageDriver.class);

  26. }


這兩種事務管理器的區別:

JDBC:這個配置就是直接使用了 JDBC 的提交和回滾設定,它依賴於從資料來源得到的連線來管理事務作用域。

MANAGED:這個配置幾乎沒做什麼。它從來不提交或回滾一個連線,而是讓容器來管理事務的整個生命週期(比如 JEE 應用伺服器的上下文)。 預設情況下它會關閉連線,然而一些容器並不希望這樣,因此需要將 closeConnection 屬性設定為 false 來阻止它預設的關閉行為。例如:

  1. <transactionManager type="MANAGED">

  2. <property name="closeConnection" value="false"/>

  3. </transactionManager>


備註:如果你正在使用 Spring + MyBatis,則沒有必要配置事務管理器, 因為 Spring 模組會使用自帶的管理器來覆蓋前面的配置。

說完了事務管理器,緊接著,我們來看看資料來源配置。

dataSource 元素使用標準的 JDBC 資料來源介面來配置 JDBC 連線物件的資源。Mybatis支援三種內建的資料來源型別,分別是UNPOOLED、POOLED和JNDI,即我們在配置<dataSource>元素的type屬性時,我們可以直接支援設定這三個值。

下面分別對這三種類型做一個簡單的說明:

(1)UNPOOLED

這個資料來源的實現只是每次被請求時開啟和關閉連線。雖然一點慢,它對在及時可用連線方面沒有效能要求的簡單應用程式是一個很好的選擇。 不同的資料庫在這方面表現也是不一樣的,所以對某些資料庫來說使用連線池並不重要,這個配置也是理想的。

UNPOOLED 型別的資料來源僅僅需要配置以下 5 種屬性:

driver : 這是 JDBC 驅動的 Java 類的完全限定名(並不是JDBC驅動中可能包含的資料來源類)。

url :這是資料庫的 JDBC URL 地址。

username : 登入資料庫的使用者名稱。

password :登入資料庫的密碼。

defaultTransactionIsolationLevel : 預設的連線事務隔離級別。

作為可選項,你也可以傳遞屬性給資料庫驅動。要這樣做,屬性的字首為“driver.”,例如:

driver.encoding=UTF8

這將通過DriverManager.getConnection(url,driverProperties)方法傳遞值為 UTF8 的 encoding 屬性給資料庫驅動。

(2)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 時適用)。 

(3)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 屬性。

至此,關於<environments>元素的相關配置使用便介紹完畢了。