背景
最近公司要求支持国产数据库达梦,但达梦与PostgreSQL的语法有一些差异,需要做一些兼容操作。
操作步骤
- 本文采用dynamic-datasource-spring-boot-starter框架处理多数据源,多数据源配置如下
spring: datasource: dynamic: primary: dm #设置默认的数据源或者数据源组,默认值即为dm strict: false #设置严格模式,默认false不启动,启动后在未匹配到指定数据源时,会抛出异常,不启动则使用默认数据源 datasource: mysql: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://xxx.xx.xx.xx:3306/aco_sip?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true username: xxxxx password: xxxx pg: driver-class-name: org.postgresql.Driver url: jdbc:postgresql://xxx.xx.xx.xx:5432/aco_sip?currentSchema=aco_sip_dev username: xxxxx password: xxxxx dm: driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://xxx.xx.xx.xx:5236/aco_sip username: xxxxx password: xxxxxx
- 本文采用mybatis作为持久层框架,需要配置DatabaseIdProvider
2.1 在SqlSessionFactoryBean#buildSqlSessionFactory中会判断容器中是否存在databaseIdProvider对象,如果存在则根据databaseIdProvider获取databaseId// jreap.dbprovider.dbTypeStr=MySQL,DM,PostgreSQL @Value("${jreap.dbprovider.dbTypeStr}") private String dbProviderStr; // 把支持的数据源设置到DatabaseIdProvider的properties中 @Bean public DatabaseIdProvider getDatabaseIdProvider() { DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider(); Properties properties = new Properties(); if (!StringUtils.isEmpty(this.dbProviderStr)) { String[] dbProviderArr = this.dbProviderStr.split(","); for(int i = 0; i < dbProviderArr.length; ++i) { String dbType = dbProviderArr[i]; if (!StringUtils.isEmpty(dbType)) { properties.setProperty(dbType, dbType.toLowerCase()); } } } databaseIdProvider.setProperties(properties); return databaseIdProvider; }
2.2 根据数据源的产品名在DatabaseIdProvider的properties中查找对应的value
2.3 DynamicContext将databaseId设置到_databaseId参数中
- 在xml中使用_databaseId参数对数据源进行区分
<select id="queryPlayNumByHour" parameterType="Map" resultType="java.util.Map"> <if test="_databaseId == 'mysql' SELECT time,count(time) as num FROM ( SELECT id,concat(DATE_FORMAT(ea.alert_time,'HH' ),':00') AS time FROM play_his_record WHERE create_time BETWEEN #{startTime} and #{endTime} ) temp GROUP BY time ORDER BY time asc </if> <if test="_databaseId == 'postgresql' or _databaseId == 'dm'"> SELECT time,count(time) as num FROM ( SELECT id,concat(to_char(create_time,'hh24'),':00') AS time FROM play_his_record WHERE create_time BETWEEN #{startTime} and #{endTime} ) temp GROUP BY time ORDER BY time asc </if> </select>
术语
上面已经介绍完mybatis多数据的SQL兼容步骤并浅析了部分源码,虽然dynamic-datasource-spring-boot-starter提供了@DS 切换数据源,但我觉得这种改动最小。