Java essay Java essay
首页
  • Java基础
  • Java进阶
  • 设计模式
  • 多线程
  • Java你不知道的小事
  • Spring初识
  • Spring进阶
  • SpringBoot基础
  • SpringBoot进阶
  • 什么是微服务
  • SpringCloud全家桶
  • Dubbo
  • SpringCloud Alibaba
  • Vue
  • 小程序
  • 博客搭建
  • 数据库
  • python
  • 大数据
  • 性能分析优化
  • 中间件
  • 云原生
  • 面试
  • 外卖霸王餐
  • 打工人的带饭生活
  • 30岁我该怎么办
友链
关于我
GitHub (opens new window)

Mr.Fire

全栈工程师
首页
  • Java基础
  • Java进阶
  • 设计模式
  • 多线程
  • Java你不知道的小事
  • Spring初识
  • Spring进阶
  • SpringBoot基础
  • SpringBoot进阶
  • 什么是微服务
  • SpringCloud全家桶
  • Dubbo
  • SpringCloud Alibaba
  • Vue
  • 小程序
  • 博客搭建
  • 数据库
  • python
  • 大数据
  • 性能分析优化
  • 中间件
  • 云原生
  • 面试
  • 外卖霸王餐
  • 打工人的带饭生活
  • 30岁我该怎么办
友链
关于我
GitHub (opens new window)
  • SQL语法

  • 数据库国产化之路

    • 聊一聊信创环境下多数据库适配方案
      • 前言
      • 1 MyBatis适配多数据库
        • 1.1 通过Mapper定义不同类型数据库的SQL
        • 1. 定义多数据库支持的 bean
        • 2. 配置文件中指定使用的具体数据库
        • 3. 重定义 Mapper
        • 1.2 通过插件机制动态代理SQL
        • 1.实现扩展插件
        • 2. 注册插件
        • 3. 修改SQL
      • 2 自定义数据库适配组件
        • 2.1 架构
        • 2.2 实现思想
      • 总结
  • 其他

  • 数据库
  • 数据库国产化之路
Mr.Fire
2022-12-09
目录

聊一聊信创环境下多数据库适配方案

# 前言

在响应国家信创的环境下,开发一款产品不仅需要适配Oracle,Mysql等主流数据库,还需要适配达梦,神通等国产数据库,适配多种数据库时,我们就需要考虑数据库兼容问题,如何让我们的代码兼容多种数据库或者说有些什么方案呢?

在开发过程中,有关数据库的操作,我们要么使用MyBatis,MyBatis-Plus,Hibernate等开源ORM框架,或者使用原生的jdbc等,那么针对不同的产品不同开发框架我们如何适配多数据库呢?

# 1 MyBatis适配多数据库

Mybatis 本身并不支持多种数据库,此时需要对 Mybatis 进行改造,这里列举两种方案:

  • 通过Mapper定义不同类型数据库的SQL
  • 通过插件机制动态代理SQL

# 1.1 通过Mapper定义不同类型数据库的SQL

Mapper 支持多数据库 SQL,即 Mapper 中即可以写支持 A 数据库的 SQL,又可以写支持 B 数据库的 SQL。

# 1. 定义多数据库支持的 bean

@Bean
public DatabaseIdProvider getDatabaseIdProvider() {
   DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
   Properties properties = new Properties();
   properties.setProperty("Oracle", "oracle");
   properties.setProperty("MySQL", "mysql");
   properties.setProperty("DM", "dm");
   databaseIdProvider.setProperties(properties);
   return databaseIdProvider;
}
1
2
3
4
5
6
7
8
9
10

# 2. 配置文件中指定使用的具体数据库

database.type=oracle
mybatis-plus.configuration.database-id=${database.type}
1
2

# 3. 重定义 Mapper

<!-- 查看某表是否存在 -->
<select id="getMtHisTableExists" resultType="java.lang.Integer">
	select count(*) ICOUNT from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA=#{dbName} and TABLE_NAME=upper(#{tableName})
</select>

<!-- oracle方言查看某表是否存在 -->
<select id="getMtHisTableExists" resultType="java.lang.Integer" databaseId="oracle">
	SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME=upper(#{tableName})
</select>

<!-- mysql方言查看某表是否存在 -->
<select id="getMtHisTableExists" resultType="java.lang.Integer" databaseId="mysql">
	SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE  TABLE_SCHEMA = #{dbName} AND TABLE_NAME=upper(#{tableName})
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 1.2 通过插件机制动态代理SQL

Mybatis 支持用插件对四大核心对象 (Executor、StatementHandler、ParameterHandler、ResultSetHandler)进行拦截,对 Mybatis 来说插件就是拦截器,用来增强核心对象的功能,Mybatis 插件提供了简单易用的扩展机制。

# 1.实现扩展插件

/**
 * @Author Mr.Fire
 * @Desc
 * @Date 2022/12/4
 */
@Intercepts(value = {
        @Signature(
                type = StatementHandler.class,
                method = "prepare",
                args = {Connection.class, Integer.class})
}
)
@Component
@Slf4j
public class DbAdapterInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        try {
            StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
            BoundSql boundSql = statementHandler.getBoundSql();
            String oldSql = boundSql.getSql();
            /**
             * 解析SQL,按照不同数据库类型修改SQL
             */
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return invocation.proceed();
        }
        return invocation.proceed();
    }
    
     @Override
    public void setProperties(Properties properties) {
        String dialect = properties.getProperty("dialect");
        log.info("mybatis intercept dialect:{}", dialect);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

注意:

如果使用的是MyBatis-Plus,只需实现com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor#beforePrepare方法,并在注册插件即可,因为Mybatis-plus插件默认代理了StatementHandler#prepare方法。

# 2. 注册插件

<configuration>
    <plugins>
        <plugin interceptor="com.fire.DbAdapterInterceptor">
            <property name="dialect" value="mysql" />
        </plugin>
    </plugins>
</configuration>
1
2
3
4
5
6
7

# 3. 修改SQL

实现按不同数据库解析SQL,并适配修改,代码省略...

# 2 自定义数据库适配组件

# 2.1 架构

# 2.2 实现思想

数据层统一定义接口,针对不同数据库分别实现不同的Starter,如果需要适配其他数据库,也能够做到灵活配置与扩展。结合SpringBoot自动装配机制,服务启动自动加载对应数据库组件,其他数据源不会初始化,也不会由此造成资源开销或冲突。至于底层如何实现适配,是用ORM框架还是原生JDBC等,可根据具体项目具体环境分析。

比如结合MyBatis实现,通过@ConditionalOnProperty注解判断进行按需自动装配对应组件:

@Configuration
@ComponentScan("com.fire.mysql")
@MapperScan(basePackages = "com.fire.mysql.dao")
@ConditionalOnProperty(name = "spring.datasource.driverClassNane", havingValue = "com.mysql.cj.jdbc.Driver")
public class AutoMySQLConfiguration {


    /**
     * sql session工厂配置
     *
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/fire/mysql/mapper/*Mapper.xml");
        return bean.getObject();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druidDataSource() {
        return new DruidDataSource();
    }

	......
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 总结

随着国产化的推进,很多项目都采用国产服务器,国产数据库,兼容适配问题急需解决,本文主要讲解一些关于多数据库适配方案,具体实现还需根据需求具体分析。

最后更新时间: 2024/12/26, 17:56:54
PgSQL非常用函数及语法
Greenplum(GP)数据库

← PgSQL非常用函数及语法 Greenplum(GP)数据库→

最近更新
01
SuperBuilder
12-29
02
30岁我该怎么办
12-29
03
关于存钱
12-29
更多文章>
Theme by Vdoing | Copyright © 2021-2025 Mr.Fire | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式