本章节介绍LightDB多发比对的整体架构及快速入门。

10.7.1. 多发+比对代理模式的架构(1对多真多发)

10.7.1.1. 架构图

../_images/arch_real_multiplex_2024-07-19_11-42-08.jpg

10.7.1.2. 场景说明

该场景主要用于单个微服务集成多发代理程序(sql-convert-runtime)后,该微服务执行sql(DQL/DML)操作时,代理程序会拦截SQL执行,并将该SQL多发到多个信创数据库执行。 如果是DML,则代理程序会获取多个信创库DML执行前预计影响的数据行,和DML执行后实际影响的数据行,并发送到消息队列中;如果是DQL,则代理程序会获取多个信创库的查询结果集,并发送到消息队列中。 之后,比对服务会以指定的mysql/oracle为基准库,与不同信创库的查询结果集进行一一比对,并记录比对差异,以比对报告的形式展示给用户查看。

10.7.2. 微服务集成多发代理(war形式,SEE2.0多发比对配置样例)

下面以SEE2.0 MariaDB–>GaussDB500的多发比对为例进行展示。

前提:

  • 已经安装好SEE2.0、多发比对服务。

  • 从官网下载最新的统一sql包,例如: 统一sql-下载(动态库),下载LightDB1.0-unisql-VXXXXXX-XX-000.zip包。 从zip里中获取 unisql.linux.aarch64.sosql-convert-runtime-fat-XX.X.jar ,用于后面的配置。

  • 从官网下载最新的统一sql比对服务包,例如: 多发比对-比对服务下载,下载LightDB1.0-comparison-VXXXXXX-XX-000.zip包。 从LightDB1.0-comparison-VXXXXXX-XX-000.zip中获取 unisql-compare-client-fat-XX.X.jar 包,用于后面的配置。

10.7.2.1. 第一步:明确业务应用相关目录

和多发比对相关的工作目录有下面几类:

1. java进程的工作目录:/home/see/tomcat/bin

该目录用于存放unisql.conf、jrescloud.properties配置文件,用于配置统一sql参数、多发参数。

如何确定微服务的工作目录(微服务是个java进程)?

  • 确定微服务进程ID:通过 ps 命令或 jps -l 命令确定微服务的进程ID,以 see 为例

    ../_images/%E9%80%9A%E8%BF%87%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E7%A1%AE%E5%AE%9A%E8%BF%9B%E7%A8%8BID.png
  • 确定进程的工作目录:通过系统默认安装的或服务自带的 jinfo 命令确定 java 工作目录,以 see 为例

    ../_images/%E9%80%9A%E8%BF%87jinfo%E5%91%BD%E4%BB%A4%E7%A1%AE%E5%AE%9A%E5%BE%AE%E6%9C%8D%E5%8A%A1%E7%9A%84%E7%94%A8%E6%88%B7%E7%9B%AE%E5%BD%95.png

2. 多发比对java依赖包的配置目录

以下目录用于存放多发比对的jar包。

  • acm服务lib目录:/home/see/tomcat/webapps/acm/WEB-INF/lib/

  • cas服务lib目录:/home/see/tomcat/webapps/cas/WEB-INF/lib/

  • server服务lib目录:/home/see/server/lib

3. 多发数据源源库配置目录

以下目前用于配置多发比对的数据源信息

  • acm源库配置路径:/home/see/tomcat/webapps/acm/WEB-INF/conf/jdbc.properties

  • cas源库配置路径:home/see/tomcat/webapps/cas/WEB-INF/classes/application.properties

4. 日志文件目录

以下是see及统一sql的日志信息,用于多发比对的对接调试。

  • app日志:/home/see/tomcat/logs/app.log

  • cas日志:/home/see/tomcat/logs/cas.log

  • 多发日志:/home/see/tomcat/logs/unisql.log

  • 统一SQL日志:/home/see/tomcat/bin/unisql.log

5、SEE应用启动目录、命令

  • 启动目录:/home/see/tomcat/bin ./startup.sh

    上面5步信息确定之后,就可以开始正式多发比对的应用对接了。

10.7.2.2. 第二步:配置统一sql、多发文件信息

在/home/see/tomcat/bin创建config文件夹,分别将unisql.conf、jrescloud.properties拷入到文件夹下,并根据实际情况进行配置,下面是see的一个参数配置例子:

1. unisql.conf参数配置

../_images/%E7%BB%9F%E4%B8%80sql%E5%A4%9A%E5%8F%91%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9B%AE%E5%BD%95.png
# 全局透传开关 0关 1开
unisql.skip = 0
# 全局异常透传开关 0关 1开
unisql.error.skip = 0
# 缓存开关 0关 1开
unisql.cache = 0
# 缓存改写sql最大条数,默认 10000条。统一 SQL 会将 SQL 转换结果进行缓存,可通过本参数配置缓存最大条数
unisql.cache.maximumSize = 10000
# 缓存过期时长,默认 900秒
unisql.cache.expireSeconds = 900
# DEBUG 日志开关 0关 1开
unisql.debug = 0
# 统一 SQL 对比 http请求的url
unisql.compare.server.url =
# 在配置项`unisql.compare.server.url`(统一 SQL 对比 http请求的url)有值的情况下,配置项`unisql.skipUnisqlRuntimeConvert` (表示是否跳过统一sql运行时sql转换,默认0表示不跳过),0关 1开
unisql.skipUnisqlRuntimeConvert = 0
# 在配置项`unisql.compare.server.url`(统一 SQL 对比 http请求的url)有值的情况下,配置项`unisql.collectMicroServiceParametersEnabled`表示是否采集微服务参数,默认0表示不采集微服务参数,0关 1开
unisql.collectMicroServiceParametersEnabled = 0
# charset 默认0 [0 utf8 1 gbk]
unisql.charset = 0
# 统一SQL自定义函数脚本执行所在的schema或database; 默认unisql
unisql.schema = unisql
# 移除列上的双引号 0 不移除 1移除
unisql.removeDoubleQuoted = 0
#gaussdb decode函数的参数为下列函数,函数之间用英文逗号分割,则decode的参数都转化为text类型
unisql.decode.parameters.funcnames =
# 是否将MySQL的create database替换成create schema,0不替换,1替换
unisql.change.database.to.schema = 1
# 转换后的sql中自定义表或字段名称结尾是否使用随机数0不随机,1随机 默认1随机
unisql.table.column.name.random = 1
# 配置关键字,对象名如果匹配到了此配置参数中配置的关键字则使用双引号包裹,每个关键字之间用逗号分隔
unisql.keyword.doublequotes = group,desc,sort,collation,order,ref
# 兼容mysqlToGuassDB [ON UPDATE current_timestamp()]列,这种属性的列需要通过配置指定,update语句根据语义处理指定列;格式:tableName:column1,column2
unisql.on.update.currentimestamp.columns =
#全局替换SQL,用于处理类似 alter table XX move tablespace XX 语法,该语法目标库不支持
unisql.global.replace.sql = select 1
#是否开启打印内存信息,0:不开启,1:开启 (注意:本参数仅适合在开发/测试环境开启观察内存使用情况,不允许在生产环境开启)
unisql.print.sysinfo = 0
# 每隔多少分钟打印一次内存dump信息(在unisql.print.sysinfo=1时生效)
unisql.print.logMemMinute = 10
# 源库是mysql时,是否识别'\'为转义字符,0:不识别,1:识别
unisql.mysql.backslash.escapes= 1
#兼容mysqlToGuassDB [auto_increment]列,这种属性的列需要通过配置指定,insert into语句会自增列截断处理,不插入自增列的值;格式:tableName1:column1;tableName2:column2;
unisql.auto.increment.column = tb_cdm_class_attrib:id;tb_rpa_flow_reference:id;tb_rpa_job_reference:id;tb_cdm_attrib_values_relation:id;tb_cdm_attrib_values:id;tb_operate_log:id;tb_see_subsystem_components:id;tb_see_id:id;tb_job_reference:id;tb_jobnet_reference:id;tb_jobnet_sched_ref:id;tb_jobnet_snapshot:id;tb_job_log:id;tb_see_candle_maintain:id;tb_influxdb_sync:id;tb_see_event_report:id;
#配置获取元数据的schema,多个用逗号隔开,如果代码里调用接口指定schemas,以代码中为准
unisql.table.column.metadata.schemas =
#定时拉取最新元数据更新到缓存中开关,开启之后会周期性的去系统表拉取最新的元数据信息缓存到本地,0:关闭,1:开启;默认关闭
unisql.table.metadata.schedule.switch = 1
#用于设置周期性拉取元数据更新到缓存的频率,当开启拉取缓存定时任务后会根据设置频率周期性拉取元数据更新到缓存,单位分钟,默认一天
unisql.table.metadata.schedule.frequency = 1440
# 源库是mysql时,指定表中字段转换后的数据类型(如果create table.../alter table ... add | modify | change...语句中表的字段和配置匹配,则使用指定的数据类型,否则使用统一SQL正常转换数据类型,见数据类型章节),格式:tableName:columnName:datatype;...,tableName为表名,columnName为字段名,datatype为数据类型,如int、varchar(100);表名,字段名大小写敏感(需要填写数据库中创建后真实名称);表名、字段名、数据类型不能为空;原始语句使用时不支持反引号中带双引号,例如: `"object"`
unisql.table.column.replace.datatype = tb_rpa_flow_params_define:default_value:text;tb_rpa_flow_params_instance:value:text;
unisql.on.update.currentimestamp.columns = tb_dssp_product_stack:update_time;tb_dssp_product_stack_config:update_time;tb_dssp_app_install_db_log:update_time;tb_dssp_product_stack_build_log:updateTime;tb_dssp_app_monitor:update_time;tb_dssp_disaster_log:update_time;tb_dssp_auto_recovery_log:update_time;tb_dssp_rcm_history:updateTime;tb_dssp_application_script:update_time;tb_canary_release_log:occurred_time;
# 适配的统一SQL目标数据库版本号,主要用于做逻辑分支判断,相同的数据库不同的版本可能会走不同的解析转换逻辑,默认为空,走默认逻辑。
unisql.target.database.version=
# 源库是mysql,查询语句中,指定表名和列名后,主要解决列名的绑定变量值为空的转化问题,会将where columnName = ? 转化成 where (columnName =? or (cast ? as dataType) is null and columnName is null),格式为: 表名1:列名1,列名2;表名2:列名1;表名3:*; 其中列名为*,指表中所有列,例如:tableName1:column1,column2;tableName2:column2;tableName3:*;
unisql.null.table.columns=
# 源库为mysql,目标库为gaussdb_oracle时。指定表的字段查询大小写不敏感,查询时会将字段和条件内容通过UPPER函数包裹。表名,字段名大小写敏感(需要填写数据库中创建后真实名称);格式为:表名1:列名1,列名2;表名2:列名1; 例如:tableName1:column1,column2;tableName2:column2;同时会在统一SQL配置目录下生成create_index.sql文件
unisql.table.column.upper.case =
# 如果配置了unisql.table.column.upper.case参数,指定表的字段查询大小写不敏感时,此参数才会生效,用于提示业务手动创建统一SQL配置目录下生成的create_index.sql文件中的索引,0 提示且不启动统一SQL ,1 提示并启动统一SQL。 默认0 提示且不启动。
unisql.table.column.upper.case.print.sql.switch = 0
unisql.lib.full-path=/home/see/unisql/unisql.linux.aarch64.so

其中,unisql.lib.full-path=/home/see/unisql/unisql.linux.aarch64.so 为统一SQL链接库,路径自定义即可。

2. jrescloud.properties参数配置

../_images/%E7%BB%9F%E4%B8%80sql%E5%A4%9A%E5%8F%91%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9B%AE%E5%BD%95.png
# 是否发送到比对服务(总开关),默认0不发送到比对服务,取值范围[0,1]
multi.sendCompareService=1
# 在发送比对服务的前提下(即配置项unisql.multi.sendCompareService=1),默认1表示采集dml前后数据变化并发送到pulsar,取值范围[0,1]
multi.onlyCompare=1
# 在发送比对服务的前提下(即配置项unisql.multi.sendCompareService=1),用于是否从线程threadlocal变量(微服务使用t3协议通讯且开启全链路日志开关)中获取全链路trace_id,默认为0表示关闭,取值范围[0,1]
multi.collect.trace.info=0
# Pulsar服务端地址,样例数据:pulsar://10.20.47.203:6650
#multi.pulsarServiceUrl=pulsar://10.20.xx.xx:6650
# Pulsar的持久化主题,主题格式:persistent://<tenant>/<namespace>/<topic>,样例数据为:persistent://public/default/recordMonitorJingji
#multi.topicName=persistent://public/default/see_develop_zxd
# 在Pulsar中,订阅(Subscription)是用于消费主题消息的标识符。订阅名称是用来标识不同消费者或消费组在订阅相同主题时的唯一标识。合法字符串即可,比如jingjiTest
#multi.subscriptionName=see_develop
# 上传数据库比对结果报告到手工的blade平台的URL(业务场景:【数风基】,联系人@李吉凯),URL格式为http://{ip}:{port}/share/v1/shareInterFace/setCompatDelivery.json
# unisql.multi.upload.manual.url=http://10.20.xx.xx:8010/share/v1/shareInterFace/setCompatDelivery.json
# http请求上送sql执行前后数据变化到到比对服务的url,默认值为空,url格式为http://ip:port/em/compare/upload/change/data
multi.send.change.data.http.url=http://10.20.xx.xx:17334/em/compare/upload/change/data

multiplex.datasource.gaussdb500_oracle.url=jdbc:opengauss://10.20.xx.xx:30100/see_duofa?currentSchema=acm&sourceDialect=mysql&targetDialect=gaussdb500_oracle&options=-c%20search_path=public,acm,acm_job
multiplex.datasource.gaussdb500_oracle.username=unisqlxx
multiplex.datasource.gaussdb500_oracle.password=unisql@123xx

其中,jrescloud.properties,需要配置以下信息:

  • 需要配置消息队列或者http请求的url(二选一),见上面例子。本次采用http的方式进行配置:multi.send.change.data.http.url=http://IP地址:端口/em/compare/upload/change/data。

  • 配置目标库的信息gaussdb500_oracle,包含url、数据库用户名、密码,详见上面。

10.7.2.3. 第三步:引入多发比对代理包(外挂方式)

需要将多发比对的依赖包分别放到下面三个文件夹目录:

../_images/%E5%A4%9A%E5%8F%91%E6%AF%94%E5%AF%B9%E4%BE%9D%E8%B5%96%E5%8C%85.png
  • acm服务lib目录:/home/see/tomcat/webapps/acm/WEB-INF/lib/

  • cas服务lib目录:/home/see/tomcat/webapps/cas/WEB-INF/lib/

  • server服务lib目录:/home/see/server/lib

10.7.2.4. 第四步:配置源库url

分别在下面两个文件下,配置多发源库的url信息、数据库用户名、密码信息、驱动类信息,具体如下:

  • acm源库配置路径:/home/see/tomcat/webapps/acm/WEB-INF/conf/jdbc.properties

  • cas源库配置路径:home/see/tomcat/webapps/cas/WEB-INF/classes/application.properties

因为acm、cas里面源库修改的地方是一致的,就以acm为例进行展示

cas.authn.jdbc.query[0].url=jdbc:mysql://localhost:3306/acm?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
cas.authn.jdbc.query[0].user=root
cas.authn.jdbc.query[0].password=E1(K7LbV0uh2nbJ6S5isMckkw==)
cas.authn.jdbc.query[0].driverClass=com.mysql.cj.jdbc.Driver

需要将SEE之前的url信息,修改为接多发的配置信息,如下所示

cas.authn.jdbc.query[0].url=jdbc:unisql:mysql://localhost:3306/acm?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false&mode=MULTIPLEX&sourceDialect=mysql&targetDialect=mysql
cas.authn.jdbc.query[0].user=root
cas.authn.jdbc.query[0].password=E1(K7LbV0uh2nbJ6S5isMckkw==)
cas.authn.jdbc.query[0].driverClass=com.hundsun.lightdb.unisql.proxy.Driver

10.7.2.5. 第五步:启动业务应用

经过前面的三个步骤,已经成功配置了多发比对的目录及参数、多发比对的jar包,接下来启动SEE应用。

../_images/SEE%E5%BA%94%E7%94%A8%E5%90%AF%E5%8A%A8%E8%84%9A%E6%9C%AC.png

10.7.2.6. 第六步:通过日志查看多发比对的运行情况

SEE应用启动后,会产生统一SQL、多发日志,用于判断配置参数是否正确、执行情况是否正常。

1、 自动会在java进程的工作目录:/home/see/tomcat/bin下生成 unisql-yymmdd-hhmmss.log日志,统一sql日志。

multiplex/images/统一SQL加载日志.png

通过该日志,可以看到已经加载在unisql.conf、jrescloud.properties文件,并能确认加载的包的版本号如24.3。

  1. 会在/home/see/tomcat/logs/unisql.log中生产多发日志

    ../_images/%E5%A4%9A%E5%8F%91%E9%83%A8%E5%88%86%E6%97%A5%E5%BF%97%E5%B1%95%E7%A4%BA.png

若多发成功,会出现红框、绿框的消息发送成功的日志。至此,基于SEE2.0的多发比对服务对接就全部完成了。

10.7.2.7. 可选模式,引用代理包(代理模式)

目前可支持两种方式来引用多发代理包(代理模式或外挂模式),外挂模式见上面第三步的配置方式;如选择代理模式,通过Maven依赖引入 sql-convert-runtime

引用方法:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <properties>
        <sql-convert-runtime.version>24.3</sql-convert-runtime.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.hundsun.lightdb</groupId>
            <artifactId>sql-convert-runtime</artifactId>
            <version>${sql-convert-runtime.version}</version>
        </dependency>
    </dependencies>

</project>

10.7.2.8. 消息队列安装(可选)

10.7.2.8.1. 下载消息队列(Pulsar)

10.7.2.8.2. 启动消息队列(Pulsar)

上传apache-pulsar-2.10.5-bin.tar.gz包到指定linux服务器进行解压安装,服务器需要预先安装1.8或以上版本JDK环境:

[lightdb@hs-10-20-30-217 ~]$tar -xzvf apache-pulsar-2.10.5-bin.tar.gz -C /usr/local/
[lightdb@hs-10-20-30-217 ~]$cd /usr/local/
[lightdb@hs-10-20-30-217 ~]$mv apache-pulsar-2.10.5/ pulsar

[lightdb@hs-10-20-30-217 ~]$vi /root/.bashrc
  export PULSAR_HOME=/usr/local/pulsar
  export PATH=$PATH:$PULSAR_HOME/bin
[lightdb@hs-10-20-30-217 ~]$source /root/.bashrc
#后台服务运行
[lightdb@hs-10-20-30-217 ~]$pulsar-daemon start standalone

10.7.2.9. 多发消息通过http方式推送到比对服务

多发消息通过http方式推送到比对服务时 不需要安装消息队列 。如需使用该模式参考多发配置项 multi.send.change.data.http.url 多发配置管理

10.7.3. 基于JRESCloud3.X开发框架 + mybatis(IDEA开发模式集成为例)

10.7.3.1. 修改统一sql配置文件:${当前工作目录}/config/jrescloud.properties

multi.run.what=2                                          // 0:不执行自动化和多发 1:执行自动化测试 2:执行多发(关联多发的源库(oracle或者mysql)的jdbcUrl中查询参数mode=MULTIPLEX) 3:执行自动化+多发(关联多发的源库(oracle或者mysql)的jdbcUrl中查询参数mode=MULTIPLEX)
multi.sendCompareService=1                               // 是否发送到比对服务(总开关),默认0不发送到比对服务,取值范围[0,1]
multi.pulsarServiceUrl=pulsar://${IP}:${PORT}            // Pulsar服务端地址,格式为:pulsar://<ip>:<port> 样例数据:pulsar://10.20.47.203:6650
multi.topicName=persistent://public/default/${TOPIC}     // Pulsar的持久化主题,主题格式:persistent://<tenant>/<namespace>/<topic>,样例数据为:persistent://public/default/recordMonitorJingji
multi.subscriptionName=${SUBSCRIPTION}                   // 在Pulsar中,订阅(Subscription)是用于消费主题消息的标识符。订阅名称是用来标识不同消费者或消费组在订阅相同主题时的唯一标识。合法字符串即可,比如jingjiTest

10.7.3.2. 模拟数据

CREATE TABLE foo (
    city_id NUMBER PRIMARY KEY,
    nation VARCHAR2(50),
    city_name VARCHAR2(100),
    city_sort NUMBER
);

INSERT INTO Foo (city_id, nation, city_name, city_sort) VALUES (1, 'China', 'Beijing', 1);
INSERT INTO Foo (city_id, nation, city_name, city_sort) VALUES (2, 'USA', 'New York', 2);
INSERT INTO Foo (city_id, nation, city_name, city_sort) VALUES (3, 'Japan', 'Tokyo', 3);
INSERT INTO Foo (city_id, nation, city_name, city_sort) VALUES (4, 'China', 'ShangHai', 4);
INSERT INTO Foo (city_id, nation, city_name, city_sort) VALUES (5, 'Canada', 'Toronto', 5);

10.7.3.3. pom依赖

 <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.hundsun.jrescloud</groupId>
            <artifactId>jrescloud-dependencies</artifactId>
            <version>3.0.21.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>com.hundsun.jrescloud.middleware</groupId>
        <artifactId>jrescloud-starter-mybatis</artifactId>
    </dependency>

    <dependency>
        <groupId>com.hundsun.jrescloud</groupId>
        <artifactId>jrescloud-starter</artifactId>
        <exclusions>
            <exclusion>
                <artifactId>log4j-slf4j-impl</artifactId>
                <groupId>org.apache.logging.log4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>com.hundsun.jrescloud</groupId>
        <artifactId>jrescloud-starter-rpc-def</artifactId>
    </dependency>

    <dependency>
        <groupId>com.oracle.ojdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>19.3.0.0</version>
    </dependency>

    <dependency>
        <groupId>cn.easyproject</groupId>
        <artifactId>orai18n</artifactId>
        <version>12.1.0.2.0</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
        <groupId>io.github.hslightdb</groupId>
        <artifactId>ltjdbc</artifactId>
        <version>42.2.24-22.4.0.3</version>
    </dependency>

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>18.0</version>
    </dependency>

    <!--sql runtime-->
    <dependency>
        <groupId>com.hundsun.lightdb</groupId>
        <artifactId>sql-convert-runtime</artifactId>
        <version>24.2.3-SNAPSHOT</version>
    </dependency>

    <!--unisql-compare-client-->
    <dependency>
        <groupId>com.hundsun.lightdb</groupId>
        <artifactId>unisql-compare-client</artifactId>
        <version>24.2.3-SNAPSHOT</version>
        <scope>system</scope>
        <systemPath>${project.basedir}/lib/unisql-compare-client-fat-24.2.3.jar</systemPath>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
    </dependency>

    <dependency>
        <groupId>com.github.jnr</groupId>
        <artifactId>jnr-ffi</artifactId>
        <version>2.2.14</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba.fastjson2</groupId>
        <artifactId>fastjson2</artifactId>
        <version>2.0.36</version>
    </dependency>

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-collections4</artifactId>
        <version>4.4</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!--gaussdb_oracle驱动-->
    <dependency>
        <groupId>com.huawei.opengauss.jdbc</groupId>
        <artifactId>gaussdbDriver</artifactId>
        <version>3.0.0-htrunk21</version>
    </dependency>

    <!--tdsql-pg-->
    <dependency>
        <groupId>com.tencentcloud.tdsql</groupId>
        <artifactId>tdsql-pg-connector-java8</artifactId>
        <version>1.1.1</version>
    </dependency>
</dependencies>

10.7.3.4. 在配置文件src/main/resources/application.properties中配置多数据源

app.name=demo-datasource
app.group=dbtest

server.port=9876
mybatis.mapperLocations=classpath:/Mapper/*.xml

hs.db.enabled=true

#postgres
hs.datasource.default.driver-class-name=org.postgresql.Driver
hs.datasource.default.url=jdbc:postgresql://ip:port/postgres
hs.datasource.default.username=username
hs.datasource.default.password=password
hs.datasource.default.validationQuery=select 1

#mysql
hs.datasource.mysql.driverClassName=com.mysql.cj.jdbc.Driver
hs.datasource.mysql.url=jdbc:mysql://ip:port/unisql?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
hs.datasource.mysql.username=username
hs.datasource.mysql.password=password

#unisql  multiplex
hs.datasource.unisql.driverClassName=com.hundsun.lightdb.unisql.proxy.Driver
hs.datasource.unisql.url=jdbc:unisql:oracle:thin:@//ip:port/orcl?sourceDialect=oracle&targetDialect=oracle&mode=MULTIPLEX
hs.datasource.unisql.username=username
hs.datasource.unisql.password=password

# 目标库为 lightdb_oracle 时,打开并修改以下连接信息
multiplex.datasource.lightdb_oracle.url=jdbc:postgresql://IP:PORT/DATABASE?sourceDialect=oracle&targetDialect=lightdb_oracle&options=-c%20search_path=public
multiplex.datasource.lightdb_oracle.username=USERNAME
multiplex.datasource.lightdb_oracle.password=PASSWORD
# 目标库为 gaussdb_oracle 时,打开并修改以下连接信息
multiplex.datasource.gaussdb_oracle.url=jdbc:opengauss://IP:PORT/DATABASE?sourceDialect=oracle&targetDialect=gaussdb_oracle&options=-c%20search_path=public
multiplex.datasource.gaussdb_oracle.username=USERNAME
multiplex.datasource.gaussdb_oracle.password=PASSWORD

10.7.3.5. 使用多数据源注解@EnableCloudDataSource注解用于开启多数据源

/**
* 多数据源注解@EnableCloudDataSource,开启多数据源功能
*/
@EnableCloudDataSource
@CloudApplication // 启动类注解
public class UnisqlMultiDataSourceApplication {

    public static void main(String[] args) {
        CloudBootstrap.run(UnisqlMultiDataSourceApplication.class, args);
    }
}

10.7.3.6. 使用数据源指定注解@TargetDataSource指定当前服务类或服务方法所使用的数据源

@Service
public class TestServiceImpl implements TestService {

    @Override
    @TargetDataSource("unisql")// 指定数据源unisql,该数据源将会使用统一SQL
    public List<Foo> selectFooByUnisql() {
        List<Foo> foo = fooMapper.select();
        return foo;
    }

}

10.7.3.7. 基于mybatis,指定数据源unisql的mapper接口方法select对应的SQL映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.middleware.dao.FooMapper">


    <resultMap id="result" type="com.demo.middleware.domain.Foo">
        <result column="city_id" property="cityId" jdbcType="INTEGER" />
        <result column="nation" property="nation" jdbcType="VARCHAR" />
        <result column="city_name" property="cityName" jdbcType="VARCHAR" />
        <result column="city_sort" property="citySort" jdbcType="VARCHAR" />
    </resultMap>

    <select id="select" resultMap="result">
        SELECT city_id, nation,city_name, city_sort FROM foo
    </select>
</mapper>

10.7.3.8. 多发测试成功输出类似如下

2024-10-09 16:28:07.498  INFO 23724 --- [nio-9876-exec-2] c.h.lightdb.unisql.utils.PulsarUtil      :
sql驱动拦截,发送sql增量变化到pulsar服务端,开始,
消息体[{"appName":"demo-datasource","databaseName":"uniq_oracle","effectRows":0,"fieldColumnNames":"city_id&&nation&&city_name&&city_sort",
"fieldColumnTypes":"numeric&&varchar&&varchar&&numeric","functionId":"","ip":"","onlyCompare":true,
"prev":[[1,"China","Beijing",1],[2,"USA","New York",2],[3,"Japan","Tokyo",3],[4,"China","ShangHai",4],[5,"Canada","Toronto",5]],
"recordTimestamp":1728548887496,"sourceDialect":"ORACLE","sql":"SELECT city_id, nation,city_name, city_sort FROM foo",
"sqlParameters":"","sqlSequence":1,"sqlType":"SELECT","tableName":"foo","targetDialect":"GAUSSDB_ORACLE",
"traceId":"86e163d7-2bf8-4ec6-92a7-d8ae287d585e","transferSql":"SELECT city_id,nation,city_name,city_sort FROM foo"}]

10.7.4. SpringBoot + JdbcTemplate(IDEA开发模式集成为例)

10.7.4.1. 数据源配置如下:

server.port=8080

mybatis.configuration.map-underscore-to-camel-case=true

spring.datasource.driver-class-name=com.hundsun.lightdb.unisql.proxy.Driver
spring.datasource.url=jdbc:unisql:oracle:thin:@//ip:port/orcl?sourceDialect=oracle&targetDialect=oracle&mode=MULTIPLEX
spring.datasource.username=username
spring.datasource.password=password

logging.level.com.hundsun.lightdb.unisql=info

# 目标库为 lightdb_oracle 时,打开并修改以下连接信息
multiplex.datasource.lightdb_oracle.url=jdbc:postgresql://IP:PORT/DATABASE?sourceDialect=oracle&targetDialect=lightdb_oracle&options=-c%20search_path=public
multiplex.datasource.lightdb_oracle.username=USERNAME
multiplex.datasource.lightdb_oracle.password=PASSWORD
# 目标库为 gaussdb_oracle 时,打开并修改以下连接信息
multiplex.datasource.gaussdb_oracle.url=jdbc:opengauss://IP:PORT/DATABASE?sourceDialect=oracle&targetDialect=gaussdb_oracle&options=-c%20search_path=public
multiplex.datasource.gaussdb_oracle.username=USERNAME
multiplex.datasource.gaussdb_oracle.password=PASSWORD

10.7.4.2. pom依赖:

 <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.3.0</version>
    </dependency>

    <!--sql runtime-->
    <dependency>
        <groupId>com.hundsun.lightdb</groupId>
        <artifactId>sql-convert-runtime</artifactId>
        <version>24.2.3-SNAPSHOT</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>com.hundsun.lightdb</groupId>
        <artifactId>unisql-compare-client</artifactId>
        <version>24.2.3-SNAPSHOT</version>
        <scope>system</scope>
        <systemPath>${project.basedir}/lib/unisql-compare-client-fat-24.2.3.jar</systemPath>
    </dependency>

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.13.0</version> <!-- 这里可以使用最新版本 -->
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.11</version>
    </dependency>

    <dependency>
        <groupId>com.github.jnr</groupId>
        <artifactId>jnr-ffi</artifactId>
        <version>2.2.14</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba.fastjson2</groupId>
        <artifactId>fastjson2</artifactId>
        <version>2.0.36</version> <!-- 这里写上你想使用的版本号 -->
    </dependency>

    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
    </dependency>

    <!--gaussdb_oracle驱动-->
    <dependency>
        <groupId>com.huawei.opengauss.jdbc</groupId>
        <artifactId>gaussdbDriver</artifactId>
        <version>3.0.0-htrunk21</version>
    </dependency>

    <!--tdsql-pg-->
    <dependency>
        <groupId>com.tencentcloud.tdsql</groupId>
        <artifactId>tdsql-pg-connector-java8</artifactId>
        <version>1.1.1</version>
    </dependency>

    <!-- 日志相关 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.30</version>
    </dependency>

    <!-- logback 依赖 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

10.7.4.3. 代码如下:

@Autowired
JdbcTemplate jdbcTemplate;

@Test
void testSpringboot() {
    // 原生oracle sql语句
    String oracleSQL = "select nation, listagg(city_name,',') within group (order by city_sort desc) citys from foo group by nation";
    // 返回gaussdb_oracle执行结果
    List<Map<String, Object>> list = jdbcTemplate.queryForList(oracleSQL);
}

10.7.4.4. 多发测试成功结果输出类似如下

2024-10-09 17:29:40.697 [main] INFO  c.h.lightdb.unisql.utils.PulsarUtil - sql驱动拦截,发送sql增量变化到pulsar服务端,结束,
消息体[{"databaseName":"uniq_oracle","effectRows":0,"fieldColumnNames":"nation&&citys","fieldColumnTypes":"varchar&&text",
"functionId":"","ip":"","onlyCompare":true,"prev":[["Canada","Toronto"],["China","ShangHai,Beijing"],["Japan","Tokyo"],["USA","New York"]],
"recordTimestamp":1728552579224,"sourceDialect":"ORACLE","sql":"select nation, listagg(city_name,',') within group
(order by city_sort desc) citys from foo group by nation","sqlParameters":"","sqlSequence":1,"sqlType":"select",
"tableName":"foo","targetDialect":"GAUSSDB_ORACLE","traceId":"31f0aa49-bcda-495d-88d8-8fb2e4f46707","transferSql":"SELECT nation,
listagg(city_name, ',') WITHIN GROUP (ORDER BY city_sort DESC) AS citys FROM foo GROUP BY nation"}],messageId=[131641:20:-1]
[{nation=Canada, citys=Token}, {nation=China, citys=ShangHai,Beijing}, {nation=Japan, citys=Tokyo}, {nation=USA, citys=New York}]