http://<服务器IP>:<druid-port>/druid/index.html如果没有开启监控,可在 Druid 配置里增加:
<property name="filters" value="stat,wall"/>
配置日志记录连接池 DEBUG 日志,便于后续排查:
<logger name="com.alibaba.druid.pool.DruidDataSource" level="DEBUG"/>
ActiveCount(活跃连接数)
PoolingCount(空闲连接数)
CreateCount / CreateErrorCount
NotEmptyWaitCount(等待线程数量)
查看数据库当前连接数:使用 DM 管理工具 (DM Management Studio) 或 SQL 方式:SELECT * FROM V$SESSION; 观察是否有大量连接处于不活跃状态。
检查有没有 STATUS='INACTIVE' 的连接非常多。
查看数据库慢查询:达梦支持查看最近执行的 SQL 及其耗时:SELECT * FROM V$SQLAREA WHERE EXECUTIONS > 0 ORDER BY ELAPSED_TIME DESC FETCH FIRST 10 ROWS ONLY; 如果有耗时非常大的语句,说明可能有慢 SQL 造成连接长时间占用。
ping <数据库IP> -n 20 观察是否有丢包或延迟突然升高。tracert <数据库IP> 确定是否有网络跳点异常。开启 slf4j 日志后,在日志中观察:
DEBUG DruidDataSource - create connection start ...
DEBUG DruidDataSource - create connection end, elapsedMillis=XXXX
如果 elapsedMillis 很大,说明是连接建立阶段慢。
同时关注:
WARN DruidDataSource - discard connection 表示失效连接被丢弃。
CreateErrorCount 表示连接创建失败次数。
<property name="keepAlive" value="true"/> 在应用中增加心跳任务,定期访问数据库保持连接活跃:(cron = "0 0/30 * * * ?")
public void keepAlive() {
jdbcTemplate.queryForObject("SELECT 1 FROM DUAL", Integer.class);
}
--查看达梦数据库连接状态
SELECT * FROM V$SESSION;
--查看达梦最近慢 SQL
SELECT * FROM V$SQLAREA WHERE EXECUTIONS > 0 ORDER BY ELAPSED_TIME DESC FETCH FIRST 10 ROWS ONLY;
--验证数据库响应
SELECT 1 FROM DUAL;
<!-- 注册Druid监控Servlet -->
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
<!-- 配置登录用户名、密码 -->
<init-param>
<param-name>loginUsername</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>loginPassword</param-name>
<param-value>123456</param-value>
</init-param>
<!-- 允许访问的IP白名单,留空表示允许所有 -->
<init-param>
<param-name>allow</param-name>
<param-value></param-value>
</init-param>
<!-- 禁止访问的IP黑名单,多个用逗号分隔 -->
<!-- <init-param>
<param-name>deny</param-name>
<param-value>192.168.1.100</param-value>
</init-param> -->
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
<!-- Druid WebStatFilter -->
<filter>
<filter-name>DruidWebStatFilter</filter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
<!-- 排除一些不需要监控的资源 -->
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DruidWebStatFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
访问 Druid 监控页面
部署后,通过浏览器访问:http://<服务器IP>:<应用端口>/druid/index.html 输入你在 web.xml 中配置的用户名(admin)和密码(123456)即可登录。
配置连接池启用stat监控:在 Druid 数据源配置中,filters 属性需要包含 stat:<property name="filters" value="stat"/>
其他可选配置:如果你想看SQL的执行情况,可以开启 SQL Merge 选项:
<property name="useGlobalDataSourceStat" value="true"/>
<property name="mergeSql" value="true"/>
create or REPLACE FUNCTION EN514(STR IN VARCHAR2(100))RETURN VARCHAR2(100)AS
BEGIN
IF STR IS NOT NULL THEN
RETURN CFALGORITHMSENCRYPT(STR, 514, '123456');
ELSE
RETURN NULL;
END IF;
END;
create or REPLACE FUNCTION DE514(STR IN VARCHAR2(100))RETURN VARCHAR2(100)AS
BEGIN
IF STR IS NOT NULL THEN
RETURN CFALGORITHMSDECRYPT(STR, 514, '123456');
ELSE
RETURN NULL;
END IF;
END;
-- 转换为SM4函数进行加密的形式
create or REPLACE FUNCTION CONVERT_ENSM4(STR IN VARCHAR2(100))RETURN VARCHAR2(100)AS
BEGIN
IF STR IS NOT NULL THEN
RETURN CONCAT('SM4(''',CFALGORITHMSDECRYPT(STR, 514, '123456'),''',''123456'',0)');
ELSE
RETURN NULL;
END IF;
END;
kingbase.conf 的 shared_preload_libraries 添加 kbcrypto,然后重启数据库,执行 CREATE EXTENSION kbcrypto; 添加加密函数 SM4CREATE OR REPLACE FUNCTION DESM4(STR IN VARCHAR2(100))
RETURN VARCHAR2(100)AS
BEGIN
IF STR IS NOT NULL THEN
RETURN convert_from(SM4(STR,'123456',1),'UTF8');
ELSE
RETURN NULL ;
END IF;
END;
DECLARE
-- 要处理的模式名
schema_name VARCHAR2(20) :='DMHR';
TYPE COL_ARRAY_TYPE IS TABLE OF VARCHAR2(100) INDEX BY PLS_INTEGER;
-- 存储表名
table_names COL_ARRAY_TYPE;
-- 存储列名
col_names COL_ARRAY_TYPE;
-- 拼接的sql语句
res VARCHAR2;
TYPE FIELD_SET_TYPE IS TABLE OF BOOLEAN INDEX BY VARCHAR2(100);
-- 存储解密字段
field_set FIELD_SET_TYPE;
TYPE FIELD_ARRAY_TYPE IS TABLE OF VARCHAR2(100);
-- 存储需解密字段数组
field_array FIELD_ARRAY_TYPE := FIELD_ARRAY_TYPE('EMPLOYEE_NAME','IDENTITY_CARD','EMAIL','PHONE_NUM','STREET_ADDRESS');
BEGIN
FOR k IN 1..field_array.count LOOP
field_set(field_array(k)):=TRUE;
END LOOP;
-- 获取指定模式下的表名
SELECT TABLE_NAME BULK COLLECT INTO table_names from DBA_TABLES where OWNER=schema_name;
FOR i IN 1..table_names.count LOOP
PRINT('--table:'||table_names(i));
BEGIN
SELECT COLUMN_NAME BULK COLLECT INTO col_names from ALL_TAB_COLUMNS WHERE OWNER=schema_name AND TABLE_NAME=table_names(i);
res := col_names(1);
FOR j IN 2..col_names.count LOOP
IF field_set.exists(col_names(j)) THEN
res := CONCAT(res, ', CONVERT_ENSM4(', col_names(j), ')', col_names(j));
ELSE
res := CONCAT(res, ', ', col_names(j));
END IF;
END LOOP;
res := CONCAT('SELECT ', res, ' FROM ', schema_name, '.', table_names(i), ';');
-- 打印sql语句
PRINT(res);
-- 执行sql语句
EXECUTE IMMEDIATE res;
END;
END LOOP;
END;
将查询结果导出为sql语句,并进行处理
sed -i -e "s/'SM4(/SM4(/g" -e "s/''/'/g" -e "s/0)'/0)/g" *.sqlpublic 模式中查找表,此时需要加上默认 public 模式名:sed -i 's/DMHR"."/DMHR".public."/g' *.sql查询数据库的表结构DDL SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEE', 'DMHR') FROM DUAL;
循环查询DDL然后一并导出
DECLARE
schema_name VARCHAR2(20) :='DMHR';
TYPE COL_ARRAY_TYPE is TABLE of VARCHAR2(100) INDEX BY PLS_INTEGER;
-- 存储表名
table_names COL_ARRAY_TYPE;
BEGIN
SELECT TABLE_NAME BULK COLLECT INTO table_names from DBA_TABLES where OWNER=schema_name;
FOR i in 1..table_names.count LOOP
print(table_names(i) || schema_name);
SELECT DBMS_METADATA.GET_DDL('TABLE', table_names(i), schema_name) FROM DUAL;
end loop;
end;
D:\Dameng\dmdbms\tool>dts_cmd_run.bat config
请输入命令:
格式: CONFIG KEYWORD=VALUE
例程: CONFIG FILE=/OPT/DM_DM.XML DESCRYPT_PASSWORD =1
-----------------------------------------------
FILE : DTS迁移配置文件路径,例如: FILE=/opt/1.xml
DESCRYPT_PASSWORD : 是否需要解密密码,0:不需要,1: 需要,默认值: 1
(DTS默认生成的配置文件登录密码都是加密的,所以需要解密,但如果手动编辑过配置文件,一般给明文,这时就不需要解密)
REPORT : EXCEL报告导出路径,指定目录
HTML_REPORT : HTML报告导出路径,指定目录
LOG : 日志导出路径,指定目录
ERR_LOG : 错误日志导出路径,指定目录
SHOW_I : 进度显示时间间隔(单位:秒),默认10s打印一次进度
DATA_TYPE_MAP_FILE : 类型映射配置文件路径,默认为FILE同目录下的datatype.xml
ERR_SQL : 迁移错误SQL导出路径,指定目录
ERR_OBJECT : 导出迁移出错的对象的路径,指定目录
D:\Dameng\dmdbms\tool>dts_cmd_run.bat config FILE=./aa.xml DESCRYPT_PASSWORD=1
迁移./aa.xml...
解析迁移的配置文件./aa.xml...
开始执行迁移./aa.xml[DM ==> SQL]...
进度:任务总数:27,已完成:27,出错:0,取消:0,剩余:0,开始时间:2025-07-19 19:07:40,结束时间:2025-07-19 19:07:40,耗时:496毫秒
./aa.xml迁移完成.
Export...
Export HTML_REPORT...
log4j:WARN No appenders could be found for logger (freemarker.cache).
log4j:WARN Please initialize the log4j system properly.
Export HTML_REPORT success(D:\Dameng\dmdbms\tool\tool\workspace\temp_data\temp\project\DTS_CMD\1953311629333524\1752923259465\transform_report_2025_07_19_19_07_52.zip)!
Total time: (19:07:52.95 - 19:07:36.84) seconds
<!--本文件由DM数据迁移工具生成,请不要手工修改,生成时间2025-07-19 13:35:14.-->
<TransformTask transform="1004" name="DM2DDL">
<Source type="db" useCustomDriver="false" useDefaultURL="true">
<Server>localhost</Server>
<Port>5236</Port>
<AuthType>0</AuthType>
<Compress>false</Compress>
<DmType>dm</DmType>
<User>SYSDBA</User>
<Password>7BAE51EA9BBCEAAD387023DAB16F5A62</Password>
</Source>
<Destination type="file">
<File encoding="UTF-8" definitionType="0" dataType="0" option="1" defineExed="false" split="false" splitSize="0"/>
</Destination>
<Config selectObjType="1">
<Strategy name="indexRename" value="true"/>
<Strategy name="createTableParallel" value="false"/>
<Strategy name="createIndexParallel" value="false"/>
<Strategy name="createPkParallel" value="false"/>
<Strategy name="allParallel" value="false"/>
<Strategy name="itemBatchSize" value="50"/>
<Strategy name="itemBufSize" value="4"/>
<Strategy name="fillThreadCount" value="2"/>
<Strategy name="taskBufSize" value="4"/>
<Strategy name="batchMaxSize" value="0"/>
<Strategy name="batchLobMaxSize" value="0"/>
<Strategy name="batchMaxTime" value="60"/>
<Strategy name="globalFldr" value="false"/>
<Strategy name="retryConnect" value="true"/>
<Strategy name="retryConnectCount" value="3"/>
<Strategy name="retryConnectInterval" value="15"/>
<Strategy name="lengthInChar" value="1.0"/>
<Strategy name="continueWhenError" value="true"/>
<Strategy name="toDate" value="false"/>
<Strategy name="threadCount" value="2"/>
<Strategy name="objectNameToUpperCase" value="true"/>
</Config>
<Mode simple="false">
<DBStrategies>
<Strategy>TRANSFORM_SCHEMAS</Strategy>
</DBStrategies>
<Schema source="DMHR" destination="DMHR">
<Strategies>
<Strategy name="schObjectStrategys" value="TRANSFORM_TABLES,TRANSFORM_VIEWS,TRANSFORM_MVIEWS,TRANSFORM_SEQUENCES,TRANSFORM_PROCEDURE_FUNCTIONS,TRANSFORM_DATABASE_AND_SCHEMA_TRIGGERS,TRANSFORM_PACKAGES,TRANSFORM_CLASSES,TRANSFORM_SYNONYM,TRANSFORM_TYPES"/>
</Strategies>
</Schema>
</Mode>
<TransformItems ItemCount="8">
<TransformItem id="0" type="table" sourceSchema="DMHR" destSchema="DMHR" source="DEPARTMENT" destination="DEPARTMENT" isDefinitionAutoGenerated="true" customColumnMap="false" partitionAsList="false"/>
<TransformItem id="0" type="table" sourceSchema="DMHR" destSchema="DMHR" source="EMPLOYEE" destination="EMPLOYEE" isDefinitionAutoGenerated="true" customColumnMap="false" partitionAsList="false"/>
<TransformItem id="0" type="table" sourceSchema="DMHR" destSchema="DMHR" source="JOB" destination="JOB" isDefinitionAutoGenerated="true" customColumnMap="false" partitionAsList="false"/>
<TransformItem id="0" type="table" sourceSchema="DMHR" destSchema="DMHR" source="JOB_HISTORY" destination="JOB_HISTORY" isDefinitionAutoGenerated="true" customColumnMap="false" partitionAsList="false"/>
<TransformItem id="0" type="table" sourceSchema="DMHR" destSchema="DMHR" source="LOCATION" destination="LOCATION" isDefinitionAutoGenerated="true" customColumnMap="false" partitionAsList="false"/>
<TransformItem id="0" type="table" sourceSchema="DMHR" destSchema="DMHR" source="REGION" destination="REGION" isDefinitionAutoGenerated="true" customColumnMap="false" partitionAsList="false"/>
<TransformItem id="0" type="table" sourceSchema="DMHR" destSchema="DMHR" source="CITY" destination="CITY" isDefinitionAutoGenerated="true" customColumnMap="false" partitionAsList="false"/>
</TransformItems>
</TransformTask>
导出的DDL sql处理:
sed -i 's/DMHR"."/DMHR".public."/g' *.sqlsed -i "s/NOT CLUSTER\s\+PRIMARY KEY(/PRIMARY KEY(/g" *.sql金仓数据库设置默认模式名:
url: jdbc:kingbase8://localhost:54321/yg?currentSchema=yg,SYS_CATALOG,在 currentSchema 指定的模式后面添加SYS_CATALOG,意图设置查询顺序,先查指定模式 yg 中的 sys_user 表search_path 类似于 Linux 中的 path 环境变量。show search_path; 默认值是 $user, public,意思就是当以某个用户登录到数据库的时候,默认就是先查找有没有和登录用户同名的 schema,没有的话再查找 public 模式。search_path 默认搜索路径来解决。kingbase.conf 中的 search_path 在末尾添加搜索路径,schema_name 为用户想优先访问的"模式名"
search_path = '"$user",schema_name,sys_catalog',修改完成后重启数据库生效ALTER DATABASE 数据库名 SET search_path to "$user", 默认选中的模式名, public, sys, sys_catalog, pg_catalog; 然后执行 select sys_reload_conf(); 重载配置文件有乱码:修改 kingbase.conf 中的 lc_messages = 'C' # locale for system error message
DM 数据守护(DM Data Watch)原理:将主库(生产库)产生的 Redo 日志传输到备库,备库接收并重新应用 Redo 日志,从而实现备库与主库的数据同步。DM 数据守护的核心思想是监控数据库状态,获取主、备库数据同步情况,为 Redo 日志传输与重演过程中出现的各种异常情况提供一系列的解决方案。
守护进程:守护进程必须和被守护的数据库实例部署在同一台机器上。守护进程可以配置为全局守护(提供实时主备、MPP 主备、读写分离集群功能)或者本地守护
MAL 系统:主要用来传输 Redo 日志,主备库之间的 Redo 日志传输,以日志包(RLOG_PKG)为单位,主库通过 MAL 系统发送 Redo 日志到备库。各种不同数据守护类型的区别,就在于主库日志包 RLOG_PKG 的发送时机,以及备库收到 Redo 日志后的处理策略。
守护进程(dmwatcher)是 DM 数据守护系统不可或缺的核心部件,是数据库实例和监视器之间信息流转的桥梁。数据库实例向本地守护进程发送信息,接收本地守护进程的消息和命令;监视器(dmmonitor)接收守护进程的消息,并向守护进程发送命令;数据库实例与监视器之间没有直接的消息交互;守护进程解析并执行监视器发起的各种命令(Switchover/Takeover/Open database 等),并在必要时通知数据库实例执行相应的操作。
守护进程支持两种守护类型:
守护进程(dmwatcher)既能以控制台方式启动,也可以配置为服务方式启动。可以在守护进程的控制台上输入命令,关闭守护进程,显示守护进程组的状态信息等
监视器(dmmonitor):用来监控守护系统内守护进程、数据库实例信息,执行用户输入命令、监控实例故障、实现自动切换等。监视器一般配置在数据库实例和守护进程以外的机器上。手动切换的守护模式必须配置确认监视器
监视器类型,监视器分为两种类型:普通监视器和确认监视器。监视器类型由配置文件(dmmonitor.ini)的 MON_DW_CONFIRM 参数来确定。MON_DW_CONFIRM 参数的默认值是 0,表示普通监视器;MON_DW_CONFIRM 参数值为 1 时,表示确认监视器。
数据库模式:DM 支持 3 种数据库模式:Normal 模式、Primary 模式和 Standby 模式。
数据库状态
归档是实现数据守护系统的重要技术手段,根据功能与实现方式的不同,DM 数据库的归档可以分为 6 类:本地归档、远程归档、实时归档、即时归档、异步归档和同步归档。其中,本地归档日志的内容与写入时机与数据库模式相关;主库 Redo 日志写入联机日志文件后,再进行本地归档;备库收到主库产生的 Redo 日志后,直接进行本地归档,同时启动Redo 日志重演。
dmarch.ini 中的 ARCH_WAIT_APPLY 或 WAIT_APPLY 配置项来设置实时归档的模式。实时归档时,ARCH_WAIT_APPLY 配置项默认值为 0,即采用高性能模式。即时归档模式中,ARCH_WAIT_APPLY 配置项默认值为 1,表示事务一致模式。任意一个备库的实时归档/即时归档失败(即使其他备库归档成功了),主库都会切换为 Suspend 状态。
MAL 系统是基于 TCP 协议实现的一种内部通信机制,具有可靠、灵活、高效的特性。DM 通过 MAL 系统实现 Redo 日志传输,以及其他一些实例间的消息通讯。
OGUID:数据守护唯一标识码,配置数据守护时,需要由用户指定 OGUID 值。其中数据库的 OGUID 在 MOUNT 状态下由系统过程 SP_SET_OGUID 设置,守护进程和监视器的 OGUID 值在配置文件中设定。同一守护进程组中的所有数据库、守护进程和监视器,都必须配置相同的 OGUID 值,取值范围为 0~2147483647。OGUID 的查询方式:SELECT OGUID FROM V$INSTANCE;
守护进程组:配置了相同 OGUID 的两个或多个守护进程,构成一个守护进程组。为方便管理,对每个守护进程组进行命名,守护进程组中的所有守护进程和监视器,必须配置相同的组名。
实时主备:实时主备由一个主库以及一个或者多个配置了实时(Realtime)归档的备库组成。实时主备系统中,主库提供完整的数据库功能,备库提供只读服务。主库修改数据产生的 Redo 日志,通过实时归档机制,在写入联机 Redo 日志文件之前发送到备库,实时备库通过重演 Redo 日志与主库保持数据同步。当主库出现故障时,备库在将所有 Redo 日志重演结束后,就可以切换为主库对外提供数据库服务。
| 主机名 | IP | 状态 | 说明 |
|---|---|---|---|
| DW_P | 192.168.1.131, 192.168.0.141 | 主库, GRP1_RT_01 | 192.168.1.131 外部服务 IP;192.168.0.141 内部通信 IP |
| DW_S1 | 192.168.1.132, 192.164.0.142 | 备库1, GRP1_RT_02 | 192.168.1.132 外部服务 IP;192.168.0.142 内部通信 IP |
| DW_M | 192.168.0.73 | 确认监视器 GRP1_RT_M |
| 实例名 | PORT_NUM | MAL_INST_DW_PORT | MAL_HOST | MAL_PORT | MAL_DW_PORT | GRP1_RT_01 |
|---|---|---|---|---|---|---|
| GRP1_RT_01 | 32141 | 33141 | 192.168.0.141 | 61141 | 52141 | |
| GRP1_RT_02 | 32142 | 33142 | 192.168.0.142 | 61142 | 52142 | |
| GRP1_RT_M | 5236 |
各端口解释:
MAL_INST_DW_PORT:实例对守护进程的监听端口
根据官方文档配置,搭建两个docker网络,一个用于内部通信,一个用于对外提供服务:
# 创建外部服务网络(对应 192.168.1.0/24)
docker network create --subnet=192.168.1.0/24 dm_external
# 创建内部通信网络(对应 192.168.0.0/24)
docker network create --subnet=192.168.0.0/24 dm_internal