Mybatis配置檔案之配置元素解析
MyBatis 可以根據不同的資料庫廠商執行不同的語句,這種多廠商的支援是基于映射語句中的 databaseId 屬性。 MyBatis 會加載不帶 databaseId 屬性和帶有比對目前資料庫 databaseId 屬性的所有語句。 如果同時找到帶有 databaseId 和不帶 databaseId 的相同語句,則後者會被舍棄。
這裡什麼意思呢 ,如果你仔細看過mybatis的官方文檔中關于XML映射檔案章節中的 select
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
下面的解釋中有一個databaseId屬性: 如果配置了 databaseIdProvider,MyBatis 會加載所有的不帶 databaseId 或比對目前 databaseId 的語句;如果帶或者不帶的語句都有,則不帶的會被忽略。新增,修改和删除都有這個屬性。例如mysql的擷取系統時間函數 NOW() 和oracle的擷取系統時間to_char(sysdate,’yyyy-mm-dd hh24:mi:ss’) 是不同的。那麼我們可以針對同一個修改可以寫兩個update語句,他們的databaseId屬性不一樣。
再比如資料庫資料分頁見MyBatis 入門(六)–分頁查詢(1)和MyBatis 入門(六)–分頁查詢(2) -插件方式他們的語句就是不一樣,就可以利用這種模式擷取目前資料,再做不同的處理。
為支援多廠商特性隻要像下面這樣在 mybatis-config.xml 檔案中加入 databaseIdProvider 即可:
配置
<databaseIdProvider type="DB_VENDOR" />
這裡的 DB_VENDOR 會通過 DatabaseMetaData#getDatabaseProductName() 傳回的字元串進行設定 見JDBC-基礎。 由于通常情況下這個字元串都非常長而且相同産品的不同版本會傳回不同的值,是以最好通過設定屬性别名來使其變短,如下:
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
在有 properties 時,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;
}
應用時可以直接通過Configuration的getDatabaseId方法來擷取目前資料的供應商。
1. 使用系統預設的規則
mybatis提供一些系統預設的配置規則,如下代碼:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="Oracle" value="oracle"/>
<property name="MySQL" value="mysql"/>
<property name="DB2" value="db2"/>
</databaseIdProvider>
其中type=”DB_VENDOR”的功能是啟用mybatis内部注冊的政策器,首先mybatis會将配置讀入到Configuration類裡面,在連結資料庫後調用getDatabaseProductName方法擷取資料庫的資訊,方法如下:
private String getDatabaseProductName(DataSource dataSource) throws SQLException {
Connection con = null;
try {
con = dataSource.getConnection();
DatabaseMetaData metaData = con.getMetaData();
return metaData.getDatabaseProductName();
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
// ignored
}
}
}
}
在上面的方法擷取到資料庫資訊後就用我們配置的name值去做比對來得到databaseId。我們把這些配置到我們的示例裡,因為我們的示例使用的是MySql資料庫,這個時如果我們用下面的代碼來擷取資料庫ID的話:
sessionFactory.getConfiguration().getDatabaseId()
則擷取的結果為:MySQL。
同樣我們也可以指定SQL的資料庫執行廠商,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yhl.mybatis.mapper.UserMapper">
<select id="findUserById" resultType="com.yhl.mybatis.model.User" parameterType="java.lang.Long" databaseId="mysql">
select id,user_name as userName,age from t_user where id = #{id,jdbcType=BIGINT}
</select>
上述代碼的select中多了一個databaseId屬性,這樣Mybatis将提供一下規則:
(1)如果沒有配置databaseIdProvider,那麼databaseId将傳回null
(2)如果配置了databaseIdProvider,那麼mybatis會使用配置的name去比對資料庫資訊,如果比對上了就傳回databaseId,如果沒有則還是傳回null
(3)如果Configuration的databaseId不為空,則mybatis隻會找到配置databaseId的SQL語句
(4)Mybatis會同時加載帶不帶databaseId屬性和比對的目前資料庫的databaseId屬性的所有語句,如果同時找到兩種語句,則不帶databaseId屬性的将被抛棄。
2. 使用自定義的規則
mybatis也提供允許自定義規則,隻要我們實作databaseIdProvider接口即可,并且實作配置即可,接下來我們看一個簡單的執行個體,首先我們定義好自定義規則類,代碼如下:
public class MyDatabaseIdProvider implements DatabaseIdProvider {
private Properties properties=null;
@Override
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String getDatabaseId(DataSource dataSource) throws SQLException {
String dbName = dataSource.getConnection().getMetaData().getDatabaseProductName();
String dbId = (String)this.properties.get(dbName);
return dbId;
}
}
然後再配置檔案中注冊我們的這個provider,如下:
<databaseIdProvider type="com.yhl.mybatis.databaseid.MyDatabaseIdProvider">
<property name="Oracle" value="oracle"/>
<property name="MySQL" value="mysql"/>
<property name="DB2" value="db2"/>
</databaseIdProvider>
這樣跟使用預設規則基本一緻。
3. mysql與oracle兩種執行個體
在這裡我們就實作mysql的擷取系統時間函數 NOW() 和oracle的擷取系統時間to_char(sysdate,’yyyy-mm-dd hh24:mi:ss’) 的的執行。
首先配置 mybatis-config.xml
<properties resource="jdbc.properties" />
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC" />
<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>
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql" />
<property name="Oracle" value="oracle" />
</databaseIdProvider>
<mappers>
<package name="com.yhl.mybatis.mapper"/>
</mappers>
接口和mapperXML檔案
package com.yhl.mybatis.mapper;
public interface TimeMapper {
String selectTime();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yhl.mybatis.mapper.TimeMapper">
<select id="SelectTime" resultType="String" databaseId="mysql">
SELECT NOW() FROM dual
</select>
<select id="SelectTime" resultType="String" databaseId="oracle">
SELECT 'oralce'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') FROM dual
</select>
</mapper>
上面的mapper檔案具有相同的id,但是他們的databaseId分别是mysql和oralce。
jdbc.properties檔案
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://127.0.0.1:3306/my_mybatis?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username = yhl
password = 1234
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:my_mybatis
username=yhl
password=1234
maxActive= 50
這個配置檔案以及登出了mysql的連結,啟用的是oralce的連結
測試類
public class Application {
public static void main(String[] args) {
SqlSession session = MybatisUtils.getSqlSession();
TimeMapper timeMapper = session.getMapper(TimeMapper.class);
timeMapper.selectTime();
}
}
結果說明
如果目前啟用的是oracle則執行databaseId=”oracle”的語句,如果mysql值執行databaseId=”mysql”的語句