
簡介:達夢資料庫適配
DM8+SpringBoot+HiKari+MyBatis3.4.6+tk.MyBatis+PageHelper

思考:
1、當使用K8、Docker容器化編排技術受到限制,當Oracle、MySql資料存盤等資料庫軟體不再向我們提供正常的服務?
2、在我們的專案工程中,若是沒有了這些核心技術提供正常的服務,如何能夠去及時地采取補救的措施,使得業務能夠平滑過渡,做到讓用戶無感知體驗?
3、是否能夠擁有自己的資料存盤解決方案,技術框架是否能夠適配,能否做到更好地兼容?
下文,小編主要以達夢-DM適配為例->常見問答Q-A的方式闡述:
Q:
DM達夢資料庫安裝,其對應版本及驅動如何選取,適配程度更佳?
A:
DM8+DmJdbcDriver18
這里提供百度云的方式供使用者下載并安裝:
https://pan.baidu.com/s/1nFBEnX3lYqIjBZo8ZPADgg
一、下載&安裝
首先,需要說明的是達夢的安裝包放一起的,沒有像Oracle那樣把客戶端獨立出來,跟windows的安裝包是一樣大的,大約1.1GB的樣子,好在的一點就是,直接解壓就可以使用,在云盤中附詳細操作指南,

解壓以后,里面有一個\source\tool\manager.exe的應用程式,可直接打開,登錄就行,
二、DM8&Client
接下來,打開DM8客戶端,可通過dm sql腳本方式去創建表,這里只是簡單創建了一張crm_version表,這里尤其需要注意的是創建表名不需要帶雙引號,達夢默認是大寫,sql方言中也不需要額外處理,若是通過DM8工具去建表建欄位或者帶小寫加雙引號創建腳本,出現雙引號則在實際的sql方言中也需要加上雙引號,否則執行sql會拋出視圖或表不存在,欄位列名不存在的例外,

若是通過Mysql或Oracle或其他資料庫,檔案等方式遷移匯入,這里記錄一下遷移程序中遇到的問題,在遷移的時候,報某些欄位超長,于是,查看了MySql中那些欄位的型別及長度,都是varchar(50) ,這里應該是遷移有些欄位,須在DM資料庫中增加位寬,在MySql中varchar是表示字符,varchar(50)表示可以存放50個字符,但是DM的默認跟Oracle是一樣的,varchar(50)表示50個位元組,這就意味著,50個位元組,如果存中文,在utf-8的字符集下,只能存最多16個,所以,如果MySql庫到DM,varchar型別,需特別留意一下,


三、DM8&DmJdbcDriver
然后,在專案工程中引入達夢資料庫驅動,SpringBoot對MySql做了集成,沒有get到對達夢資料庫做集成,小編這里采用的jdk1.8,安裝的達夢資料庫也是DM8,所以這里引入:
DmJdbcDriver18,其相對于DmJdbcDriver17作出了很大的改進,
i、本地引入的方式
在pom.xml檔案中,引入依賴jar
<!-- 達夢資料庫驅動 --><dependency><groupId>com.dm</groupId><artifactId>DmJdbcDriver18</artifactId><version>1.8</version><scope>system</scope><systemPath>${project.basedir}/src/main/resources/lib/DmJdbcDriver18.jar</systemPath></dependency>

ii、nexus私服引入的方式
在pom.xml檔案中,引入依賴jar
<!-- 達夢資料庫驅動 --><dependency><groupId>com.dm</groupId><artifactId>DmJdbcDriver18</artifactId><version>1.8</version></dependency>

說明:這里的groupId坐標引數,可由使用者自行在nexus中upload創建宣告,然后在pom.xml中引入相關坐標即可,
擴展:若是需要從本地deploy到nexus或是先獲取本地倉庫.m2的包->nexus倉庫的包->aliyun maven倉庫的包,為了解決開發程序中jar包拉取例外等問題,則在maven中settings.xml中可這樣去配置:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"><!-- 本地倉庫 --><localRepository>D:/.m2</localRepository><mirrors><mirror><id>nexus</id><mirrorOf>*</mirrorOf><name>yd nexus</name><url>http://ip:port/repository/maven-public/</url></mirror></mirrors><mirror><id>alimaven</id><mirrorOf>central</mirrorOf><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url></mirror><profiles><profile><id>nexus</id><repositories><repository><id>maven-snapshots</id><url>http://ip:port/repository/maven-snapshots/</url><releases><enabled>false</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository><repository><id>maven-releases</id><url>http://ip:port/repository/maven-releases/</url><releases><enabled>true</enabled></releases><snapshots><enabled>false</enabled></snapshots></repository></repositories></profile></profiles><servers><server><id>nexus</id><username>yxd179</username><password>yxd179</password></server><server><id>maven-releases</id><username>yxd179</username><password>yxd179</password></server><server><id>maven-snapshots</id><username>yxd179</username><password>yxd179</password></server></servers><activeProfiles><activeProfile>nexus</activeProfile></activeProfiles></settings>
四、配置達夢資料庫的資訊

說明:這里采取Nacos注冊中心去管理專案工程中用到的一些配置資訊,Nacos的介紹具體可參考小編微信公眾號:每天譯點曉知識
https://mp.weixin.qq.com/s/UyQ6wHGMyrGnDRwNZaJz0Q
至此,達夢資料庫環境安裝,相關版本及其依賴的選取跟引入,配置資訊完畢,
Q:
在DM8達夢資料庫適配的專案工程中,多資料庫兼容+資料庫連接池+ORM映射框架+分頁相關控制元件?
A:
HiKari+MyBatis3.4.6+tk.MyBatis+PageHelper
hikari:資料庫連接池-Hikari3.4.2,
mybatis:ORM(物件關系映射)框架,內部封裝了 JDBC,不需要花費精力處理加載驅動、創建連接、創建 statement 等繁雜程序,
// 驅動-連接地址-賬號-密碼等資訊String driverClassName = "dm.jdbc.driver.DmDriver";String url = "jdbc:dm://localhost:5236/";String username = "yxd179";String password = "yxd179";// 加載驅動Class.forName(driverClassName);// 獲取資料庫連接物件Connection con = (Connection) DriverManager.getConnection(url,username,password);// 獲取資料庫操作物件PreparesStatement ps = con.preparesStatement("SELECT COUNT(*) FROM TEST;");// 執行sqlResultSet rs= ps.executeQuery();// 這里還可以獲取到資料庫產品名稱DatabaseMetaData metaData = (DatabaseMetaData) con.getMetaData();// 這里為后續提到的在xml指定達夢的databaseId奠定基礎System.out.println("資料庫產品名稱:" + metaData.getDatabaseProductName());最后需關閉連接close,釋放資源->rs-ps-con.
tk.mybatis:mybatis定制的第一大業務增強庫,
pagehelper:分頁控制元件,mybatis定制的第二大業務增強庫,
Q:
DM8達夢資料庫在多資料庫切換中,其databaseId如何能夠被ORM映射框架MyBatis指定訪問?
A:
當 mybatis 在進行 mapper 注入時,當前 sql 方法的 databaseId 和當前資料源的 databaseId 一樣?當前 sql 方法的 databaseId 和當前資料源的 databaseId 不一樣?當前 sql 未配置 databaseId?

其實,這都是需要我們care到的,當mybatis裝配時,若是同一個方法被找到多條sql時,首先,會優先使用 databaseId 相同的 sql,若是沒有 databaseId 相同的sql,其次,再使用未配置 databaseId 的 sql,而databaseId 未對應的 sql 不會使用,



i、當獲取到的資料源資訊為mysql,則執行圖一中批量插入insertBatch方法;
ii、當獲取到的資料源資訊為db2,則執行圖二中批量插入insertBatch方法;
iii、當獲取到的資料源資訊為oracle,則執行圖三批量插入insertBatch方法,
上例,這樣我們就能極其簡易的指定 databaseId,很多小伙伴肯定會說為什么需要這樣去指定?其背后的原理又是怎樣的,我們是否能夠擴展并自定義 databaseId?框架這層的應用真能夠提供的這么 perfect 嗎?
在上一個Q-A中,我們已經get到了資料庫產品的名稱,可以從資料源連接物件中去獲取,不妨從這里出發,這里先提出一點 little 猜想,mybatis既然能夠支持mysql,oracle,db2等等資料庫,那么其他關系型資料庫?肯定是提供一些這樣的入口可以去擴展的,只是各種框架的適配程度不一樣,都在不斷兼容,網上關于這塊的資料并不全面,基于資料庫產品名稱這條線索,于是,小編封裝了獨立的配接器sdk,可作達夢等關系型資料庫適配,當然不同型別的資料庫,后續在sdk中去擴展兼容都是可以做到的,
說明:有興趣的童鞋請點擊譯點主頁,可公眾號后臺留言,welcome together^_^
i、通過組態檔屬性方式指定databaseId:
mybatis:
mapper-locations: classpath*:mapper/**.xml
configuration:
database-id: dm8
ii、 通過configuration配置類,往容器注入Bean方式指定databaseId:
/**
* @Auther: X.D.Yang
* @Date: 2021/4/1 13:14
* @Description:
*/
@Configuration
public class DatabasesConfig {
private static final Logger logger = LoggerFactory.getLogger(DatabasesConfig.class);
@Bean
public DatabaseIdProvider getDatabaseIdProvider() {
DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
Properties p = new Properties();
logger.info("Join DM8 databaseId Starting...");
p.setProperty("DM DBMS", "dm8");
//p.setProperty("MySQL", "mysql");
databaseIdProvider.setProperties(p);
logger.info("Join DM8 databaseId Start completed.");
return databaseIdProvider;
}
}
iii、mybatis-config.xml配置方式指定databaseId:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
<property name="DM DBMS" value="dm8" />
</databaseIdProvider>
至于小編封裝的獨立sdk,其主要思想結合SpringBoot-自動裝配-條件配置:
@SpringBootApplication->@SpringBootConfiguration(@Configuration注解,宣告為spring的配置類)、@EnableAutoConfigurationspringboot(啟動最關鍵的注解)、@ComponentScan(對包進行掃描)
i、其中@EnableAutoConfiguration注解會讀取所有classpath:META-INF/Spring.factories,取key為org.springframework.boot.autoconfigure.EnableAutoConfiguration下的所有value,注冊到核心容器,完成自動配置類的加載,
讀取:spring提供的工具類-SpringFactoriesLoader>>>第一個引數是個Class物件,決定讀取的key,為class物件的全類名,第二個引數是ClassLoader物件,決定從哪里開始找這個檔案,然后讀取classpath:META-INF/spring.factories檔案,

ii、自動配置類上有大量自動配置生效的條件,比如依賴是否被引入,springboot采用了默認代替配置的策略,當然也可更改默認配置,比如修改application.yml>yamlproperties組態檔,手動往容器中注冊特定bean,注冊一些實作特殊介面的類,比如實作WebMvcConfigurer介面的類,自動配置即向容器注冊組件,實作了特殊介面的組件,影響spring的生命周期,
/**
* @Auther: X.D.Yang
* @Date: 2021/3/15 20:39
* @Description:
*/
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLoggedInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
@Bean
public LoggedInterceptor getLoggedInterceptor() {
return new LoggedInterceptor();
}
}

//WebMvcConfigurer介面還有很多實作方法
@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
public WebMvcConfigurerAdapter() {
}
public void addInterceptors(InterceptorRegistry registry) {
}
}
其中,
@ConditionalOnClass:一些類是否存在當前類路徑下,
@ConditionalOnProperty:相應的配置欄位滿足,
@ConditionalOnMissingBean:容器中沒有某個bean,
這里我們著重看一下mybatis提供的自動配置包-MybatisAutoConfiguration,生效條件:需引入mybatis相關的依賴,核心容器中只有一個DataSource,在DataSource自動配置完成后才生效等等條件,并且還開啟了配置類@EnableConfigurationProperties(MybatisProperties.class)

上述構造方法:當前物件被實體化時,會被注入一系列的bean-MybatisProperties物件...
iii、mybatis為我們注冊了SqlSessionFactory,SqlSessionTemplate,以及為每個@Mapper注冊了一個Mapper實作類-MyBatis->@Autowired注入一個Mapper,
當我們自己為容器中注入SqlSessionFactory物件,從容器中取dataSource(當引入spring-boot-starter-jdbc時會自動配置)作為引數,創建一個SqlSessionFactoryBean物件,該物件是個工廠-生產SqlSessionFactory,這里通過SqlSessionFactoryBean物件的一系列set方法,最后呼叫getObject方法來獲取到SqlSessionFactory物件,其中生成SqlSessionFactory需要的Configuration物件,這里也可以取代mybatis的主組態檔-sqlSessionFactoryBean.setConfiguration方法,


而SqlSessionTemplate的創建,則取上述注入的SqlSessionFactory,new SqlSessionTemplate物件即可,至于對MyBatis原始碼Debug有興趣的可以參考小編之前的文章>https://blog.csdn.net/yxd179/article/details/84568401
記錄:在適配的程序中還試出了達夢的幻讀,達夢和Oracle一樣默認的隔離級別都是讀提交;還有特別需要注意的就是,在資料庫中varchar型別的欄位,比如在mysql中定義varchar(50),在寫滿的情況下為50個字符,到了達夢這邊最多也就是varchar(150),當然可自行指定位寬,小編用的字符集是UTF-8,每個字符占三個位元組,乘以三倍,就肯定是裝得下的,目前達夢適配現有的框架為:
HiKari+MyBatis3.4.6+tk.MyBatis+PageHelper
ok,now,接入sdk適配后,啟動的效果,大致如下:

這里,主要對sql分頁查詢作下闡述:簡單的分頁可通過手寫sql limit...,首先統計count總數,然后計算分頁等相關資訊,這里不著重說明,當然sql分頁控制元件也是可以去擴展的,PageHelper分頁,其主要原理:首先將傳遞的引數設定到page這個物件中去,然后會接著將page的副本存放入ThreadLoacl中,保證分頁時引數互不影響,通過mybatis提供的攔截器,獲取ThreadLocal中的值,重新拼裝分頁sql陳述句,
接入之后,我們在控制臺輸出dm sql日志,看一下列印的sql-偽列分頁:

在DM8中正常執行sql,獲取結果集:

而在MySql中,簡單limit分頁輸出是這樣的:

<附注>Debug分頁控制元件原始碼,其實也很容易理解,分頁最終是這樣去拼裝的:
protected BoundSql getPageBoundSql(Object parameterObject) {String tempSql = sql;String orderBy = PageHelper.getOrderBy();if (orderBy != null) {tempSql = OrderByParser.converToOrderBySql(sql, orderBy);}tempSql = localParser.get().getPageSql(tempSql);return new BoundSql(configuration, tempSql, localParser.get().getPageParameterMapping(configuration, original.getBoundSql(parameterObject)), parameterObject);}
//當然,這里有很多其他的Parser,這里可擴展,可兼容,去適用于不同的資料庫public String getPageSql(String sql) {StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120);sqlBuilder.append("select * from ( select tmp_page.*, rownum row_id from ( ");sqlBuilder.append(sql);sqlBuilder.append(" ) tmp_page where rownum <= ? ) where row_id > ?");return sqlBuilder.toString();}
Q:
DM8、MySql、Oracle等資料庫切換程序對比,除了各自方言異同,是否還有其他新發現?
A:
結論是肯定的,這里僅根據控制臺輸出的sql日志來看,PageHelper.startPage(0,100)VSPageHelper.startPage(1,100)
引出這樣一個小問題-思考:上述這倆者在DM8、MySql或者其他關系型資料庫中會出現不一樣的效果嗎?若是,又如何去fix^_^
附:由于時間等原因,闡述不一定俱全,本文暫時就到這里,對于達夢這塊,搜索可用資源較少,希望對各位讀者,在適配達夢資料庫程序中能夠有所幫助,歡迎提出寶貴建議^_^
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/276168.html
標籤:其他
