>愛(ài)上mybatis是因?yàn)樽杂勺栽诘膕ql映射, SQL在手, 一切我有的那種感覺(jué)!
>然而由于其非完整ORM框架原因, 導(dǎo)致我們掌握了SQL的自由, 卻失去了ORM兼容多庫(kù)的天然特性
>本文章告訴你, 如何使 mybatis 輕量支持?jǐn)?shù)據(jù)庫(kù)兼容?
` Beacuse of some reason , I write this line , just like because of some reason , you read this line !`
>溫馨提示: 由于此方法過(guò)于簡(jiǎn)單粗暴, 所以面世較晚 , 當(dāng)你的mybatis版本高于3.1時(shí),才可以用哦!
#實(shí)現(xiàn)方式
##第一處
###applicationContext.xml or mybatis-config.xml
####applicationContext.xml
```
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
??class="org.springframework.beans.factory.config.PropertiesFactoryBean">
oracle
mysql
db2
sybase
sqlserver
```
>先配置一個(gè)vendorProperties, 存儲(chǔ)productName和其對(duì)應(yīng)的別名, productName為key, 別名為value , 然后配置一個(gè)databaseIdProvider, 關(guān)聯(lián)vendorProperties, 使其拿到配置. 最后再sqlSessionFactory中添加
> ``即可
####mybatis-config.xml
```
????????"http://mybatis.org/dtd/mybatis-3-config.dtd">
????
????????
????????
????
????????
????????
????????
????????
```
直接加個(gè)``節(jié)點(diǎn)就行了
>友情提示, 使用mybatis-config.xml方式時(shí), 必須確保改配置文件中定義了environments及其transactionManager和dataSource,否則databaseIdProvider將不生效, 也就是說(shuō), 使用spring管理mybatis時(shí), 此方式失效!
##第二處
###UserMapper.xml
```
????????PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
????????"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
????????SELECT *
????????FROM users
ORDER BY id ASC
????????SELECT *
????????FROM users
ORDER BY id ASC
```
>經(jīng)過(guò)本人實(shí)測(cè), mybatis查找 statement 的邏輯是 : 先找有databaseId的, 是否有對(duì)應(yīng)的, [1] 若有, 則直接調(diào)用(友情提示:別強(qiáng)行寫(xiě)2個(gè)相同的databaseId且statement id也相同), [1] 若無(wú), 則查找是否有 未指定databaseId的 statement , [2] 若有, 則調(diào)用, [2] 再?zèng)]有, 就報(bào)錯(cuò)了 !
>也就是說(shuō), 你完全可以以一種數(shù)據(jù)庫(kù)為主, 如MySQL為主, Oracle則是某些模塊使用, 即寫(xiě)xml時(shí), 一般都直接不寫(xiě)databaseId, 唯有Oracle那個(gè)模塊才寫(xiě)上 databaseId="oracle" .比如樓主公司, 就是這種情況! 而另一種情況則是, 整個(gè)項(xiàng)目都需要兼容, 那修改量就相對(duì)大一些, 需要2個(gè)statement分別標(biāo)明不同的databaseId.
#原理簡(jiǎn)單剖析
>經(jīng)過(guò)本人不辭辛苦的查看源碼: SqlSessionFactoryBean, 對(duì)應(yīng)的databaseIdProvider代碼, 最終發(fā)現(xiàn)這么一段代碼:
```
Environment var29 = new Environment(this.environment, this.transactionFactory, this.dataSource);
configuration.setEnvironment(var29);
if(this.databaseIdProvider != null) {
????try {
????????configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
????} catch (SQLException var22) {
????????throw new NestedIOException("Failed getting a databaseId", var22);
????}
}
```
這段代碼是將dataSource傳給databaseIdProvider,讓databaseIdProvider獲取databaseId,并設(shè)置到mybatis中!
>下面看databaseIdProvider如何獲取databaseId
```
private String getDatabaseProductName(DataSource dataSource) throws SQLException {
????????Connection con = null;
????????String var4;
????????try {
????????????con = dataSource.getConnection();
????????????DatabaseMetaData metaData = con.getMetaData();
????????????var4 = metaData.getDatabaseProductName();
????????} finally {
????????????if(con != null) {
????????????????try {
????????????????????con.close();
????????????????} catch (SQLException var11) {
????????????????????;
????????????????}
????????????}
????????}
????????return var4;
????}
```
原來(lái)最終時(shí)通過(guò)connection.getMetaData.getDatabaseProductName()方法得到一個(gè)東東,就是配置中properties的 key , 然后看下面這段代碼:
```
private String getDatabaseName(DataSource dataSource) throws SQLException {
????????String productName = this.getDatabaseProductName(dataSource);
????????if(this.properties != null) {
????????????Iterator i$ = this.properties.entrySet().iterator();
????????????Entry property;
????????????do {
????????????????if(!i$.hasNext()) {
????????????????????return null;
????????????????}
????????????????property = (Entry)i$.next();
????????????} while(!productName.contains((String)property.getKey()));
????????????return (String)property.getValue();
????????} else {
????????????return productName;
????????}
????}
```
>根據(jù)connection獲得了當(dāng)前數(shù)據(jù)源真實(shí)的productName, 如MySQL, Oracle .而后通過(guò)配置進(jìn)來(lái)的properties判斷是否包含這個(gè) key , 若有進(jìn)行返回! 無(wú)則直接返回productName !
以上的源碼都是分析databaseId時(shí)如何獲取, 如何被設(shè)置到mybatis中的, 至于mybatis如何根據(jù)databaseId判斷對(duì)應(yīng)的statement, 那還不是小意思, 不過(guò)本人小白一個(gè), 沒(méi)有看過(guò)mybatis源碼, 對(duì)其不熟悉, 要找這塊源碼太費(fèi)時(shí)間, 浮躁的社會(huì)我也不能幸免 !