基于cola5.0的基础设施层的多数据库切换方案思路

1、目标

底层适配多种数据库,实现简单切换就能实现数据库的迁移,对领域层往上无感知。

现实场景:

让一个系统可以平滑的部署到不同的数据库上,方便项目的交付,减少二次开发和项目交付的时间和人力成本。

2. 技术架构设计

2.1 整体架构图

复制代码
+---------------------+
|     Application     |  应用层
+----------+----------+
           |
+----------v----------+
|     Domain Layer    |  领域层
+----------+----------+
           |
+----------v----------+
| Infrastructure Layer|  基础设施层
+----------+----------+
     |     |      |
+----+--+ +--+---+ +--+---+
|MySQL  | |Oracle| |PGSQL|  数据库适配层
+-------+ +------+ +------+

3. 关键实现方案

前置条件:

1)单表的操作全使用mybatisPlus来完成,复杂的在自定义sql

2)多表的操作也可以使用类似JOOQ的代码工具实现

更复杂的自定义sql写到resource下不同数据库对应的文件夹中。

1、sql映射文件的切换:

spring的配置文件中配置要使用的DB类型名称,利用mybatis或mybatisPlus的xml扫描路径,利用springEL动态扫描不同的路径sql(在resource 下不同数据库有对应名称的sql文件夹)。

例如:

复制代码
spring:
  datasource:
    db-type: mysql
  

mybatis-plus:
  mapper-locations: classpath*:mybatis/${spring.datasource.db-type}/**/*Mapper.xml

2、repositoryImpl的切换:

继续使用domain层的repository接口操作持久层,不同的数据库定义不同的实现类去做各自的实现。有个DataBaseConfig类,里面使用静态内部类定义不同的数据库启用condition(实现spring的Condition接口),然后配合spring的@Condition 注解实现创建使用不同的repositoryImpl

扩展:加个repository接口的抽象实现类,用于写公共的持久化方法,非公共的写到各自的实现类中。

复制代码
/**
 * 用户抽象实现类
 * 包含通用的方法实现,具体数据库的特定方法由子类实现
 */
public abstract class AbstractUserRepositoryImpl implements UserRepository{
  
}

@Repository
@Conditional(DatabaseConfig.MysqlCondition.class)
public class MysqlUserRepositoryImpl extends AbstractUserRepositoryImpl {

    @Autowired
    private MySqlUserMapper mySqlUserMapper;

}

/**
 * 达梦数据库的用户仓库实现
 */
@Repository
@Conditional(DatabaseConfig.DmCondition.class)
public class DmUserRepositoryImpl extends AbstractUserRepositoryImpl {

    @Autowired
    private DmUserMapper dmUserMapper;

}


/**
 * 数据库配置类
 * 实现数据库类型的条件判断,用于@Conditional注解
 */
public class DatabaseConfig {
    
    /**
     * 达梦数据库条件类
     */
    public static class DmCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String dbType = context.getEnvironment().getProperty("spring.datasource.db-type", "dm");
            return "dm".equalsIgnoreCase(dbType);
        }
    }
    
    /**
     * MySQL数据库条件类
     */
    public static class MysqlCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String dbType = context.getEnvironment().getProperty("spring.datasource.db-type", "dm");
            return "mysql".equalsIgnoreCase(dbType);
        }
    }

}

3、依赖的切换:

利用maven profiles 实现按需加载不同的驱动,避免随着后面兼容数据库的增多,导致打包后包体积过大。例如

复制代码
<profiles>
    <!-- 达梦数据库 -->
    <profile>
        <id>dm</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <dependencies>
            <dependency>
                <groupId>com.dameng</groupId>
                <artifactId>DmJdbcDriver18</artifactId>
                <version>8.1.2.141</version>
            </dependency>
        </dependencies>
    </profile>
    
    <!-- MySQL数据库 -->
    <profile>
        <id>mysql</id>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.33</version>
            </dependency>
        </dependencies>
    </profile>
    
    <!-- Oracle数据库 -->
    <profile>
        <id>oracle</id>
        <dependencies>
            <dependency>
                <groupId>com.oracle.database.jdbc</groupId>
                <artifactId>ojdbc11</artifactId>
                <version>21.8.0.0</version>
            </dependency>
        </dependencies>
    </profile>
  
</profiles>

4、使用

4.1 增加新的数据库实现

1)增加数据库类型枚举定义

2)增加repository的实现类并实现方法

3)增加对应的sql映射文件

4)增加对应的连接依赖和修改数据库连接的4个属性

4.2 切换到已有的数据库实现

1)配置文件中修改数据库类型名称

2)修改数据库连接的4个属性

相关推荐
zandy101114 分钟前
多租户SaaS架构下的BI数据隔离与权限治理体系
数据库·架构·数据加密
数字孪生家族36 分钟前
3DGS 数据编辑单体化技术:将高斯重建转化为结构化数字空间资产
数据库·3d·高斯泼溅·空间智能应用
广州灵眸科技有限公司1 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) 系统操作-线进程操作
数据库·单片机·嵌入式硬件·算法·php
石一峰6992 小时前
驱动:私有数据为什么要在三个地方各挂一遍?
数据库·python·算法
ClouGence3 小时前
跨云、跨地域数据同步,这样更省心
数据库·sql·saas
TDengine (老段)3 小时前
TDengine 函数完整参考 — 聚合、时序、字符串、时间、数学
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
TDengine (老段)4 小时前
昆仑数智选择 TDengine TSDB,提升页岩气生产运行可视化与精细化管理能力
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
陆水A4 小时前
【问数系统】SQL跑对了图表却空了?打通问数系统最后1公里的3个API坑
大数据·数据库·自然语言处理·big data·etl工程师
霸道流氓气质4 小时前
SpringBoot中使用字典驱动的动态路由示例
java·spring boot·后端
海外数字观察家4 小时前
品未云:泰国华商批发零售一体化 ERP,破解本土软件适配难题|CSDN 技术分享
网络·数据库·人工智能