达梦数据库适配问题
达梦数据库适配采坑记
达梦数据库适配采坑记 问题一
问题描述:
字段内容超长错误:
问题详解:
达梦数据库和Oracle同样,对字段的长度有严格的规范,当然Mysql也是有的,但是默认是不启用的,哪怕超出了,也会自动扩容,但是Oracle和达梦是不会的;
解决方案:
方案一:
对数据库的字段长度进行变更;
方案二:
变更数据类型;
方案三:
约束字段长度,或者进行截取处理
问题二:
问题描述:
语句分析错误,不识别[`]符号
问题详解:
在Mysql中[`]符号是为了防止和Mysql的系统字段冲突,标识这个一个普通字段,但是在达梦数据库中,不识别这个符号;
解决方案:
方案一:
采用MyBatis的拦截器对SQL进行拦截处理;
方案二:
对XML中的SQL里面的[`]符号进行删除替换(推荐);
问题三:
问题描述:
不是GROUP by 表达式
问题详解:
因为在Oracle和达梦中查询字段必须在分组中出现,所以报错
解决方案:
方案一:
修改代码,去掉Sql中查询的不是分组的字段,通过代码二次查询实现;
问题四:
问题描述:
问题详解:
解决方案:
方案一:
案例:
问题五:
问题描述:
on duplicate key update语法分析错误
问题详解:
属于Mysql专用语法,在Oracle和达梦中是不支持的
解决方案:
方案一:
使用Merge修改(不推荐)
案例:
修改前:
insert into sys_logininfo(info_id,infp_name) values(1,2) on duplicate key update info_id=2,infp_name=’aaa’;
修改后:
merge into sys_logininfo t1 using(
select 1 info_id,2 infp_name from dual
) t2 on
(t1.info_id=t2.info_id)
WHEN MATCHED THEN
update set info_id=2,infp_name=’aaa’ WHEN NOT MATCHED THEN INSERT VALUES (1,2);
遗留问题:
在使用druid连接池时,报了一个错,但是并不影响
MERGE INTO sys_logininfo t1 US', expect MERGE, actual IDENTIFIER pos 82, line 1, column 1, token IDENTIFIER MERGE
- 1.
- 2.
方案二:
通过代码拆分insertOrUpdate 拆分为insert和update
问题六:
问题面熟:
前端展示空白,后端没有报错
样例:
问题详解:
因为Mysql迁移到了达梦,所以字段全部由小写转换为大写,本身返回Bean是没有问题的,但是一些特殊的SQL返回的是List所以结果Key全部为大写,所以前端调用时为小写,所以无法展示;
解决方案:
方案一:
前端修改代码;
方案二:
定义一个VO,把后端的返回的List,转成定义的VO,返回前端;
问题七:
问题描述:
达梦数据库concat函数不认识[“]符号
问题详解:
在Mysql中无论是[‘][“]都是识别的,但是在达梦中只识别[‘];
解决方案:
方案一:
用[‘]替换项目中的[“];
样例:
修改前:
select * from aa where a like CONCAT(“%”,”龙”,”%”);
修改后:
select * from aa where a like CONCAT(‘%’,’龙’,’%’);
问题八:
问题描述:
达梦数据库查询列别名时使用[‘’]包裹,是会报错的
问题详解:
达梦数据库在做关键字区分时采用[“”]包裹
解决方案:
方案一:
采用[“”]替换[‘’]
样例:
不带关键字
修改前:
select aa as ‘a’ from aaa;
修改后
select aa as a from aaa;
带关键字
修改前:
select aa as ‘index’ from aaa;
修改后:
select aa as “index” from aaa;
问题九:
问题描述:
使用concat直接包裹字段,会报错,无法解析的表达式
问题详解:
达梦不支持无条件的拼接
解决方案:
方案一:
去掉concat
样例:
修改前:
select concat(aaa) as a from aa;
修改后:
select aaa as a from aa;
达梦数据库DM8安装初体验-Windows环境 | 达梦技术社区
dminit 命令行工具配置如下:
dminit path=d:\dmdbms\data CASE_SENSITIVE=1
查询大小写敏感设置的情况:
SELECT CASE_SENSITIVE(); --结果为 1 是大小写敏感,结果为 0 是不敏感
开启SQL助手功能
默认情况下,SQL 助手的功能是没有启用的。所以我们需要在管理工具的选项中打开相关设置。选择窗口->选项->查询分析器->编辑器。
达梦数据库中排除屏蔽系统保留字的方法有两种:
第一种:修改数据库dm.ini中参数EXCLUDE_RESERVED_WORDS
第二种:配置客户端dm_svc.conf文件,添加KEYWORDS配置项(推荐)
达梦数据库DM8安装初体验-Windows环境 | 达梦技术社区
https://eco.dameng.com/document/dm/zh-cn/pm/jdbc-rogramming-guide.html
https://eco.dameng.com/document/dm/zh-cn/start/dm-install-docker.html
https://eco.dameng.com/document/dm/zh-cn/start/java-development.html
https://eco.dameng.com/document-preview/dm/zh-cn/app-dev/java-jdbc-old
https://eco.dameng.com/document/dm/zh-cn/app-dev/java-MyBatis-Plus-frame.html
https://eco.dameng.com/document/dm/zh-cn/start/dm-start-stop-windows.html
2.9 关闭 numa
2.9.1 关闭的意义
NUMA(Non-Uniform Memory Access)架构是为了解决多 CPU 下内存访问冲突,即不再将整个物理内存作为一个整体,而是根据不同的 CPU 区分不同的内存块,如 2 颗 CPU 每颗 CPU 使用 64G 内存。当 NUMA 参数 zone_reclaim_mode
设置为 1 时,内核将要求多路 CPU 尽量从距离较近的系统内存节点(服务器的整体内存在 numa 架构下将被分成若干个节点)分配内存,而不是在整个服务器可访问内存的范围内进行内存分配。因此,在较高内存占用压力下,内存申请会触发内存频繁回收整理的机制,严重影响系统整体性能(长期处于内核态 sys 很高),进而可能导致 SQL 卡顿问题的发生。
2.12 调整 limits.conf 参数
2.12.1 参数文件介绍
在 Linux、Solaris、AIX 和 HP-UNIX 等系统中,操作系统默认会对程序使用资源进行限制。如果不取消对应的限制,则数据库的性能将会受到影响。
2.12.2 调整项介绍
- core file size 建议设置为 unlimited。并将 core 文件目录放到大的空间目录存放。
- data seg size 建议设置为 1048576 以上或 unlimited,此参数过小将导致数据库启动失败。
- file size 建议设置 unlimited (无限制),此参数过小导致数据库安装或初始化失败。
- open files 建议设置为 65536 以上或 unlimited。
- virtual memory 建议设置为 1048576 以上或 unlimited,此参数过小将导致数据库启动失败。
- max user processes 最大线程数这个参数建议修改为 10240。
2.13 调整 system.conf 参数
2.13.1 参数文件介绍
system.conf
为系统和服务管理的配置文件,当运行系统实例时,systemd 将读取这个配置文件 system.conf
,相反读取 user.conf
。
达梦数据库服务注册为系统服务的进程,如通过 systemctl 或者 service 方式设定随机自启动的数据库服务,其能打开的最大文件描述符、proc 数量等不受 limits.conf
控制,需要修改 /etc/systemd/system.conf
文件。
2.14.1 参数文件介绍
nproc 是操作系统级别对每个用户创建的进程数的限制。文件路径为 /etc/security/limits.d/nproc
。不同操作系统文件名略有不同,其中麒麟 10 中是 nproc.conf
;centos6 中是 90-nproccentos
,centos7 中是 20-nproc.conf
。/etc/security/limits.conf
可配置限制文件打开数,系统进程等资源在该文件配置中写的最大用户进程数是受 /etc/security/limits.d/proc.conf
配置上限影响的。
2.14.2 调整项介绍
soft 表示软限制,hard 表示硬限制,nproc 进程数,nofile 文件数。
Copyroot@nf2180034:/root#cd /etc/security/limits.d
root@nf2180034:/etc/security/1imits.d#1s
nproc.conf
root@nf2180034:/etc/security/1imits.d#cat nproc.conf
dmdba soft nproc 65536
dmdba hard nproc 65536
2.14.3 具体命令
Copy##编辑配置文件 /etc/security/limits.d/nproc.conf
[root@dm~]# vi /etc/security/limits.d/nproc.conf
##添加配置:
dmdba soft nproc 65536
dmdba hard nproc 65536
##确定是否生效:
[dmdba@~]# ulimit -u
65536
若在 /etc/security/limits.conf
修改最大用户进程数,则注释掉 /etc/security/limits.d/90-nproc.conf
文件中的相关内容即可。
2.15 调整 profile 参数
2.15.1 参数文件介绍
/etc/profile
文件与环境变量相关,修改后对所有用户起作用。登录 Linux 时,会首先启动 /etc/profile
文件,然后再启动用户目录下的 ~/.bash_profile
、 ~/.bash_login
或 ~/.profile
文件中的其中一个。 /etc/profile
为全局(公有)配置,不管是哪个用户,登录时都会读取该文件。.~/.profile
若 bash 是以 login 方式执行时,读取 ~/.bash_profile
,若它不存在,则读取 ~/.bash_login
,若前两者不存在,则读取 ~/.profile
。
- CASE_SENSITIVE
标识符大小写敏感。当大小写敏感时,小写的标识符应当用 "" 括起,否则被系统自动转换为大写;当大小写不敏感时,系统不会转换标识符的大小写,在标识符比较时也不能区分大小写。取值:Y、y、1 表示敏感;N、n、0 表示不敏感。默认值为 Y 。可选参数。
DM 为了兼容不同的数据库,在初始化数据库的时候有一个参数字符串比较大小写敏感,用于确定数据库对象及数据是否区分大小写,默认为区分,不可更改。建议从 MYSQL 和 SQLSERVER 迁移过来的系统,使用大小写不敏感,ORACLE 迁移过来的系统,使用大小写敏感,以便和原来系统匹配。
生产环境中该参数依据用户实际需求进行指定。
更多内容可参考:详解 DM 数据库字符串大小写敏感。
检查数据库实例大小写敏感信息
SELECT SF_GET_CASE_SENSITIVE_FLAG();
--1 为大小写敏感,0 为大小写不敏感
复制
场景一:初始化数据库实例为大小写敏感库
sp_create_system_packages(1);
SELECT SF_GET_CASE_SENSITIVE_FLAG();
--1
复制
DDL 操作
create table test3(ID int,name char(20));
select dbms_metadata.get_ddl('TABLE','test3','SYSDBA')from dual;
复制
--未找到对象或不允许查询系统定义的内部索引
select dbms_metadata.get_ddl('TABLE','TEST3','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."TEST3"
(
"ID" INT,
"NAME" CHAR(20)) STORAGE(ON "MAIN",CLUSTERBTR);
*/
----------------------------------
create table test6(id int,"name" chat(20));
复制
select dbms_metadata.get_ddl('TABLE','TEST6','SYSDBA') from dual;
/*
CREATE TABLE "SYSDBA"."TEST6"
(
"ID" INT,
"name" CHAR(20)) STORAGE(ON "MAIN",CLUSTERBTR;
*/
create table "test1"(id int);
create table test1("id" int);
create table test2("id" int,id int);
复制
select dbms_metadata.get_ddl('TABLE','test1','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."test1"
(
"ID" INT) STORAGE(ON "MAIN",CLUSTERBTR);
*/
复制
select dbms_metadata.get_ddl('TABLE','TEST1','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."TEST1"
(
"id" INT) STORAGE(ON "MAIN",CLUSTERBTR);
*/
复制
select dbms_metadata.get_ddl('TABLE','TEST2','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."TEST2"
(
"id" INT,
"id" INT) STORAGE(ON "MAIN",CLUSTERBTR);
*/
复制
总结
大小写敏感的数据库中,创建表时:
- 如果不对表名或列名添加"",那么表名和列名都自动转换为大写形式;
- 如果对表名或列名添加"“,会固定书写时的大、小写形式,书写时采取的是小写形式,那么就定型为小写形式,其他不添加”"的则自动转换为大写形式,无论书写时采取的是大写形式或小写形式。
- 同名的数据库对象,如果大小写不同,那么则为两个不同的对象,字段同样如此;
- 一个表中,即使是相同的字段名,只要大小写不同,允许存在同名且不同大小写形式的字段。
OTHERS 操作
drop table test1;
create table test1(id int,name char(20));
复制
--导出元数据
select dbms_metadata.get_ddl('TABLE','TEST1','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."TEST1"
(
"ID" INT,
"NAME" CHAR(20)) STORAGE(ON "MAIN",CLUSTERBTR);
*/
--进行 DML 操作
insert into sysdba.test1 values(1,'an');
update sysdba.test1 set id=100 where id=1;
delete from sysdba.test1 where id=100;
commit;
--4 条语句执行成功
insert into sysdba.test1("id","name") values(1,'an');
--无效的列名[id]
update sysdba.test1 set id=100 where "id"=1;
--无效的列名[id]
delete from sysdba.test1 where "id"=100;
--无效的列名[id]
复制
总结
大小写敏感的数据库中,DML 或 DDL 操作时:
- 如果不对表名或列名添加"",那么表名和列名都自动转换为大写形式;
- 对表进行 DML 操作时,如果没有小写形式的字段,不能采取小写加""的形式指定过滤字段,会被认定为无效的字段;
- 如果对表名或列名添加"“,会固定书写时的大、小写形式,”“中是大写形式,则过滤字段就是大写字段,”"中是小写字段,则过滤字段就是小写字段;
- 对其进行 DML 操作时,需要利用""指定表名和字段名,否则默认会认定以大写形式去查询对象。
- 查询时,''和""界定符中字符串区分大小写,界定符中的字符串若是大写形式,那仅查询这个大写形式的对象,若是或小写形式,那仅查询这个小写形式的对象,DML 操作依旧。
场景二:数据库为大小写不敏感库
sp_create_system_packages(1);
SELECT SF_GET_CASE_SENSITIVE_FLAG();
--0
复制
DDL 操作
create table test3(ID int,name char(20));
select dbms_metadata.get_ddl('TABLE','test3','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."test3"(
"ID" INT,"name" CHAR(20)) STORAGE(ON "MAIN",CLUSTERBTR);
*/
复制
select dbms_metadata.get_ddl('TABLE','TEST3','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."test3"(
"ID" INT,
"name" CHAR(20)) STORAGE(ON "MAIN",CLUSTERBTR);
*/
复制
create table test6(id int,"name" char(20));
select dbms_metadata.get_ddl('TABLE','TEST6','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."test3"("id" INT,"name" CHAR(20))
STORAGE(ON "MAIN",CLUSTERBTR);
*/
复制
create table "test1"(id int);
--执行成功
create table test1("id" int);
--执行失败 对象[test1]已存在
create table TEST1("id" int);
--对象[test1]已存在
create table test2("id" int,id int);
--执行失败 列[id]已存在
复制
select dbms_metadata.get_ddl('TABLE','test1','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."test1"
(
"id" INT) STORAGE(ON "MAIN", CLUSTERBTR);
*/
复制
select dbms_metadata.get_ddl('TABLE','TEST1','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."test1"
(
"id" INT) STORAGE(ON "MAIN", CLUSTERBTR);
*/
复制
总结
大小写不敏感的数据库中,创建表时:
- 无论对不对表名或列名添加"",表名和列名的大小写形式不会发生变化,大写形式就是大写形式,小写形式就是小写形式;
- 不允许存在同名的数据库对象,即使大小写不同,默认也只能存在一个;
- 一个表中,也不允许相同的字段名,即使大小写不同;
- 查询时,''和""界定符不区分大小写,界定符中的查询或过滤条件即使是大写或小写,都可以查询到预期的结果集。
OTHERS 操作
drop table test1;
create table test1(id int,name char(20));
--导出元数据
复制
select dbms_metadata.get_ddl('TABLE','TEST1','SYSDBA')from dual;
/*
CREATE TABLE "SYSDBA"."test1"
(
"id" INT,
"name" CHAR(20)) STORAGE(ON "MAIN", CLUSTERBTR);
*/
--进行 DML 操作
insert into sysdba.test1 values(1,'an');
update sysdba.test1 set id=100 ehere id=1;
delete from sysdba.test1 where id=100;
commit;
--4 条语句执行成功
insert into sysdba.test1("id","name") values(1,'an');
--执行成功
update sysdba.test1 set id=100 where ID=1;
--执行成功
select * from TEST1 where NAME='AN';
/*
id name
100 an
*/
delete from sysdba.test1 where NAME='AN';
--执行成功
select * from TEST1;
-null
复制
总结
大小写不敏感的数据库中,DML 或 DDL 操作时:
- 无论对不对表名或列名添加"",表名和列名的大小写形式不会发生变化,大写形式就是大写形式,小写形式就是小写形式;
- 不允许存在同名的数据库对象,即使大小写不同,默认也只能存在一个;
- 一个表中,也不允许相同的字段名,即使大小写不同;
- 查询时,''和""界定符不区分大小写,界定符中的查询或过滤条件即使是大写或小写,都可以查询到预期的结果集,进行 DML 操作时依旧。
4.3 SQL 语句优化
4.3.1 索引
索引是一种特殊的数据库结构,由数据表中的一列或多列组合而成,可以用来快速查询数据表中有某一特定值的记录。
索引结构:最常见的索引结构为 B*树索引
1. 优化 GROUP BY
提高 GROUP BY 语句的效率,可以在 GROUP BY 之前过滤掉不需要的内容。
2. 用 UNION ALL 替换 UNION
当 SQL 语句需要 UNION 两个查询结果集合时,这两个结果集合会以 UNION ALL 的方式被合并,在输出最终结果前进行排序。用 UNION ALL 替代 UNION, 这样排序就不是必要了,效率就会因此得到提高。
3. 用 EXISTS 替换 DISTINCT
当 SQL 包含一对多表查询时,避免在 SELECT 子句中使用 DISTINCT,一般用 EXISTS 替换 DISTINCT 查询更为迅速。
4. 多使用 COMMIT
可以在程序中尽量多使用 COMMIT,这样程序的性能得到提高,需求也会因为 COMMIT 所释放的资源而减少。
COMMIT 所释放的资源:
- 回滚段上用于恢复数据的信息;
- 被程序语句获得的锁;
- redo log buffer 中的空间;
- 为管理上述 3 种资源中的内部花销。
5. 用 WHERE 子句替换 HAVING 子句
避免使用 HAVING 子句,HAVING 只会在检索出所有记录之后才对结果集进行过滤,这个处理需要排序、总计等操作,可以通过 WHERE 子句限制记录的数目。on、where、having 三个都可以加条件子句,其中,on 是最先执行,where 次之,having 最后。
- on 是先把不符合条件的记录过滤后才进行统计,在两个表联接时才用 on;
- 在单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,where 和 having 结果是一样的,但 where 比 having 快
- 如果涉及到计算字段,where 的作用时间是在计算之前完成,而 having 是在计算后才起作用,两者的结果会不同;
- 在多表联接查询时,on 比 where 更早起作用。首先会根据各个表之间的关联条件,把多个表合成一个临时表后,由 where 进行过滤再计算,计算完再由 having 进行过滤。
6. 用 TRUNCATE 替换 DELETE
当删除表中的记录时,在通常情况下, 回滚段用来存放可以被恢复的信息。如果没有 COMMIT 事务,会将数据恢复到执行删除命令之前的状况;而当运用 TRUNCATE 时,回滚段不再存放任何可被恢复的信息。当命令运行后,数据不能被恢复。因此很少的资源被调用,执行时间也会很短。
7. 用 EXISTS 替换 IN、用 NOT EXISTS 替换 NOT IN
在基于基础表的查询中可能会需要对另一个表进行联接。在这种情况下, 使用 EXISTS (或 NOT EXISTS )通常将提高查询的效率。在子查询中,NOT IN 子句将执行一个内部的排序和合并。无论在哪种情况下,NOT IN 都是最低效的(要对子查询中的表执行一个全表遍历),所以尽量将 NOT IN 改写成外连接( Outer Joins )或 NOT EXISTS。
--优化前
SELECT A.* FROM TEMP(基础表) A WHERE AGE > 0
AND A.ID IN(SELECT ID FROM TEMP1 WHERE NAME ='TOM');
--优化后
SELECT A.* FROM TEMP(基础表) A WHERE AGE > 0
AND EXISTS(SELECT 1 FROM TEMP1 WHERE A.ID= ID AND NAME='TOM');
5.2.1 MySQL 迁移到 DM 的存储过程运算结果与原库不一致
【问题描述】
MySQL 中执行 SELECT SIGN(65^4)^1
,运算结果为 0;而 DM 数据库中执行结果为 11。
【问题分析】
此问题是由于 MySQL 和 DM 数据库运算优先级不一致导致。
DM 数据库运算优先级:
MySQL 数据库运算优先级:
因此 MySQL 中该运算 SELECT SIGN(65^4)^1
,实际执行顺序为:select (sign(65^4)^1)
。
DM 中该运算 SELECT SIGN(65^4)^1
,实际执行顺序为:select sign(65^4)^1
。
1. JDBC 中使用 setNull 方法给 varchar 类型绑定空值报错:字符串转换出错
【问题描述】:通过如下语句给 varchar 类型绑定空值报错:字符转换出错。
String sql = "select * from sysobjects where name=?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setNull(1, 0);
stmt.execute();
conn.commit();
【问题解决】:出现该报错是由于达梦默认 null 和空串不等价,解决办法如下:
- 修改 dm.ini,令 COMPATIBLE_MODE = 2;
- 重启数据库服务后生效
2. jdbc 程序中如何获取存储过程的元数据信息
【问题描述】:利用如下程序获取存储过程的元数据信息,执行完后获取的元数据信息为空,jdbc 程序代码片段如下:
DatabaseMetaData dbMetaData = conn.getMetaData();
ResultSet rs = dbMetaData.getProcedureColumns("PERSONPACKAGE", dbMetaData.getUserName(), "ADDPERSON", null);
ResultSet rs = dbMetaData.getProcedureColumns("PERSONPACKAGE", dbMetaData.getUserName(), "ADDPERSON", null);
System.out.println("Get getProcedureColumns:");
while (rs.next()) {
System.out.println("PROCEDURE_NAME:"+rs.getString("PROCEDURE_NAME"));
System.out.println("COLUMN_NAME:"+rs.getString("COLUMN_NAME"));
}
【问题解决】:需要 JDBC 打开兼容 Oracle 模式,在 jdbc 的 url 串中添加 compatibleMode=oracle。
例如:jdbc:dm//localhost:5236?compatibleMode=oracle
4. JDBC 驱动连接数据库报错:failed to initialize ssl
【问题描述】:由于未配置 SSL 环境而使用 SSL 登录。
【问题解决】:可以关闭 SSL 参数。使用 sysdba 登录执行以下语句:
SP_SET_PARA_VALUE(2,'ENABLE_ENCRYPT',0);
然后重启达梦数据库服务即可。
1. 快速设置使得在 mybatis 下对象不用添加双引号。
【问题解决】:
- 设置大小写不敏感,此方法会影响查询结果集,因为其对结果集匹配也不区分大小写,需要根据业务自行评估是否可行。
- 在 mysql 数据库中,对象名默认是小写,达梦对象名默认是大写,在用达梦 DTS 工具迁移的时候,去掉“保持对象名大小写”的勾选,使对象名自动转换成大写,在 mybatis 查询的时候,即不需要加双引号强调小写。
注意
mybatis-plus3.0 之后的版本才支持 DM 数据库,在选择使用 mybatisplus-jar 包版本时请注意版本号。
2. NET 程序中使用 DmBulkCopy 对象执行时报错
【问题描述】:.NET 程序中使用 DmBulkCopy 对象执行时报错:
##具体报错信息如下:
Unhandled exception. Dm.DmException (0x80004005): The fastloading dll not loading!
at Dm.DmFldr.Initilize(DmConnProperty props, String desttable, DmBulkCopyOptions op, Int32 rows, DataTable table)
at Dm.DmBulkCopy.WriteToServer(DataTable table)
【问题分析】:DmBulkCopy 对象用于快速批量装载数据。实现 IDisposable 接口。该功能依赖 DM 安装目录 \bin 下的 dmfldr_dll.dll 等动态链接库,需要拷贝到应用程序的执行目录。
驱动文档里的说明:
DmProvider 文件夹中是完整的 DmProvider 驱动文件。使用 DmProvider 的 DmBulkCopy 对象,需要引用 dmfldr_dll.dll 以及此 dll 依赖的其他库。
添加 dmfldr_dll.dll 引用时会报错,这种方法无效。
【问题解决】:在 Path 环境变量里面加上达梦的 bin 目录:
报错“加密模块加载失败”
【问题分析】:libeay32.dll 这个加密动态库找不到。
【问题解决】:在系统环境变量中配置达梦的 bin 目录,或者把 dm 的安装目录环境变量设置到最前面或者把这个动态库以及依赖文件拷贝到程序目录下面或者 system32(可以拷贝 bin 目录下所有动态库文件)
- 版本对比
对比项 | 标准版 | 企业版 | 安全版 |
---|---|---|---|
最大连接数 | 25 | 无限制 | 无限制 |
最大物理 CPU 数量 | 2 | 无限制 | 无限制 |
最大逻辑 CPU 核数 | 32 | 无限制 | 无限制 |
使用时间 | 无限制 | 无限制 | 无限制 |
硬件平台支持 | Windows 全系列、Linux 全系列、 龙芯、飞腾、申威、泰山、 海光、兆芯、Power、安腾等 |
Windows 全系列、Linux 全系列、 龙芯、飞腾、申威、泰山、 海光、兆芯、Power、安腾等 |
Windows 全系列、Linux 全系列、 龙芯、飞腾、申威、泰山、 海光、兆芯、Power、安腾等 |
最大存储容量 | 500G | 无限制 | 无限制 |
单表最大行数 | 1 亿 | 无限制 | 无限制 |
大表最大列数 | 1024 | 2048 | 2048 |
列存储 | 不支持 | 支持 | 支持 |
分区表 | 不支持 | 支持 | 支持 |
并行查询 | 不支持 | 支持 | 支持 |
闪回查询 | 不支持 | 支持 | 支持 |
分析函数与 自定义聚集函数 |
不支持 | 支持 | 支持 |
虚拟函数 VPD | 不支持 | 支持 | 支持 |
DBMS_SQL 包 | 不支持 | 支持 | 支持 |
存储过程调试功能 | 不支持 | 支持 | 支持 |
XML 支持 | 不支持 | 支持 | 支持 |
JSON 支持 | 不支持 | 支持 | 支持 |
空间数据库支持 | 不支持 | 支持 | 支持 |
全文索引支持 | 不支持 | 支持 | 支持 |
DBLINK 功能 | 不支持 | 支持 | 支持 |
DMHS 支持 | 不支持 | 支持 | 支持 |
数据守护集群 DATAWATCH |
不支持 | 支持 | 支持 |
读写分离集群 DMRWC |
不支持 | 支持 | 支持 |
共享存储集群 DMDSC |
不支持 | 支持 | 支持 |
大规模并行处理集群 DMMPP |
不支持 | 支持 | 支持 |
数据复制 Data Replication |
不支持 | 支持 | 支持 |
企业管理工具 DEM |
不支持 | 支持 | 支持 |
备份还原接口 SBT | 不支持 | 支持 | 支持 |
嵌入式 pro*c | 不支持 | 支持 | 支持 |
外部函数扩展 | 不支持 | 支持 | 支持 |
外部表 | 不支持 | 支持 | 支持 |
通讯加密 | 不支持 | 支持 | 支持 |
存储加密 | 不支持 | 支持 | 支持 |
加密引擎 | 不支持 | 不支持 | 支持 |
三权分立 | 不支持 | 支持 | 支持 |
四权分立 | 不支持 | 不支持 | 支持 |
自主访问控制 | 不支持 | 支持 | 支持 |
强制访问控制 | 不支持 | 不支持 | 支持 |
审计和实时侵害检测 | 不支持 | 不支持 | 支持 |
客体重用 | 不支持 | 不支持 | 支持 |
资源限制 | 不支持 | 支持 | 支持 |
附录 1 数据字典
DM 提供非常多的数据字典,供用户更好的了解系统的详细信息。数据字典表的模式名为 SYS。例如:SYS.SYSOBJECTS。
例 1 查看系统表 SYS.SYSOBJECTS。
一、达梦入门技术文档
新手直接看达梦入门技术文档即可
二、达梦数据库
1、介绍
达梦数据库管理系统是达梦公司推出的具有完全自主知识产权的高性能数据库管理系统,简称DM,它具有如下特点:通用性、高性能、高可用、跨平台、高可扩展
2、与MySQL的区别
(1)创建表的时候,不支持在列的后面直接加comment
注释,使用 COMMENT ON IS
代替,如:
COMMENT ON TABLE xxx IS xxx
COMMENT ON COLUMN xxx IS xxx
(2)不支持 date_sub
函数,使用 dateadd(datepart,n,date) 代替,其中,datepart可以为:year(yy,yyyy),quarter(qq,q),month(mm,m),dayofyear(dy,y),day(dd,d),week(wk,ww),weekday(dw),hour(hh), minute(mi,n), second(ss,s), millisecond(ms),例子:
select dateadd(month, -6, now());
select dateadd(month, 2, now());
(3)不支持 date_format
函数,它有三种代替方法:
A: 使用 datepart 代替:语法:datepart(datepart, date),返回代表日期的指定部分的整数,datepart可以为:year(yy,yyyy),quarter(qq,q),month(mm,m),dayofyear(dy,y),day(dd,d),week(wk,ww),weekday(dw),hour(hh), minute(mi,n),second(ss,s), millisecond(ms),例子:
select datepart(year, '2023-04-13 08:45:00'); --2023
select datepart(month, '2022-12-13 08:45:00'); --12
B: 使用 date_part 代替,功能和 datepart 一样,写法不同,参数顺序颠倒,且都要加引号,例子:
select date_part('2023-12-13 08:45:00', 'year');--2023
select date_part('2022-12-13 08:45:00', 'mm'); -- 12
C: 使用 extract 代替,语法:extract(dtfield from date),从日期类型date中抽取dtfield对应的值,dtfield 可以是 year,month,day,hour,minute,second,例子:
select extract(year from '2023-12-13 08:45:00'); --2023
select extract(month from '2022-12-13 08:45:00'); --12
(4)不支持 substring_index 函数, 使用 substr / substring 代替,语法:
substr(char[,m[,n]])
substring(char[from m[ for n]])
(5)不支持 group_concat 函数,使用 wm_concat 代替,例子:
select wm_concat(id) as idstr from persion ORDER BY id ;
(6)不支持 from_unixtime 函数,使用 round 代替,语法:
round(date[,format])
(7)不支持 case-when-then-else ,例如:
select case when id = 2 then "aaa" when id = 3 then "bbb" else "ccc" end as test from (select id from person) tt;
(8)current_timestamp 的返回值带有时区,例子:
select current_timestamp();
2023-04-37 14:34:18.433839 +08:00
3、数据迁移
三、JAVA项目连接DM数据库
1、引入依赖
<dependency>
<groupId>com.dameng</groupId>
<artifactId>Dm8JdbcDriver18</artifactId>
<version>8.1.1.49</version>
</dependency>
2、Nacos中配置
四、MySQL转达梦sql注意事项
1、``不可以用
`type` 需要去掉``
2、达梦数据库错误代码-4080:不是 GROUP BY 表达式
1、GROUP BY 和 ORDER BY 一起使用时,ORDER BY 要在 GROUP BY 的后面。
2、在 select 需要查询的语句中选中的字段,必须出现在 GROUP BY 子句中
使用 GROUP BY 要注意以下问题:
1.在 GROUP BY 子句中的每一列必须明确地命名属于在 FROM 子句中命名的表的一列。分组列的数据类型不能是多媒体数据类型;
2.分组列不能为集函数表达式或者在 SELECT 子句中定义的别名;
3.当分组列值包含空值时,则空值作为一个独立组;
4.当分组列包含多个列名时,则按照 GROUP BY 子句中列出现的顺序进行分组;
5. GROUP BY 子句中至多可包含 255 个分组列; 6. ROLLUP\CUBE\GROUPING SETS 组合不能超过 9 个。
3、达梦数据库报错「-2106」:无效的表或视图名
1、确认程序连接达梦的用户名,确认该用户是否有select这张表的权限;
2、检查这张表的所属模式,如果模式名与用户名相同,可以用select * from 表名;如果模式名与用户名不同,需要使用 select * from 模式名.表名; 的语法。
3、nacos中url使用schema指定模式:
注意:模式不可以使用-连字符,最好使用下划线
4、DATE_SUB函数
expr 在达梦中需要加单引号,建议使用到这类函数时数字加上单引号。
count(YEAR(create_time) = YEAR(DATE_SUB(NOW(),INTERVAL 1 YEAR)) OR NULL) as lastYearNum
改为:
count(YEAR(create_time) = YEAR(DATE_SUB(NOW(),INTERVAL '1' YEAR)) OR NULL) as lastYearNum
5、SUM 的参数必须为数值类型,这里做了逻辑运算就不是数值了。
6、yearweek 函数
达梦数据库没有 yearweek ,使用 year 函数 week 函数 结合
select yearweek('2022-01-01'); //mysql写法
select concat(year('2022-01-01'), week('2022-01-01'));//达梦写法
7、count中进行比较,导致错误
如何修改:使用sum即可
8、迁移报错
解决方案:迁移外键的时候,取消“保留引用表原有的模式信息”功能,选择迁移对象->点击转换
9、MySQL 的ON DUPLICATE KEY UPDATE语句在达梦数据库中使用的方式
10、无法解析的成员访问表达式[UUID]
解决方案:
1、在imp业务层设置了uuid
2、在 DM 数据库中可以使用以下两种方法生成 UUID:
使用 SYS_GUID() 函数生成 UUID,该函数返回一个唯一标识符,可以作为列的默认值或者手动插入。
代码示例:
CREATE TABLE your_table (
id VARCHAR2(40) DEFAULT SYS_GUID() PRIMARY KEY,
...
);
使用 rawtohex(sys_guid()) 函数将 UUID 转换为字符串,然后插入表中。
代码示例:
INSERT INTO your_table (id, ...) VALUES (rawtohex(sys_guid()), ...);
注意,使用第二种方法时,需要将 UUID 转换为字符串,因为 DM 数据库中没有原生的 UUID 类型。
11、Activiti7.X支持达梦数据库
注意事项持续更新中…
【DM】达梦数据库与MySQL适配_达梦数据库 mysql-CSDN博客
达梦8数据库更新语句包含单引号双引号引起转义字符执行失败解决方法全网唯一_达梦单引号转义-CSDN博客
达梦数据库更新语句包含单引号双引号引起执行失败解决方法全网唯一
如果一个更新的UPDATE更新语句的内容包含单引号’,会引起执行错误!
错误的类型不止这一种,但是都是因为内容里面包含转义字符单引号引起
解决方法一:外部单引号 内部数据单引号替换为双引号
把SQL里面内容人工调整成一行
update test1 set nasen='select * FROM a WHERE NAME="NASEN"'
解决方法二:外部同意用单引号,内部采用REPLACE函数实现转义
把SQL里面内容人工调整成一行
SELECT REPLACE('select * from nasen where name="{var}"','"','''')
update test1 set createSql=REPLACE('select * from nasen where name="{aasda}"','"','''') where id=35;
这种方法就实现了遇到更新语句包含单引号导致执行失败的问题了
三、达梦8怎么实现MYSQL的ON UPDATE CURRENT_TIMESTAMP COMMENT ‘更新时间’
我们实际工作中会用到业务用到当数据被修改的时候同时记录当前修改的时间,在MYSQL的时候用到
gxsj` timestamp NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
达梦在达梦8怎么实现呢这里用到触发器实现
1、我们建一个测试的表
CREATE TABLE "nasen_test"
(
"ID" BIGINT NOT NULL,
"SCSJ" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
"STATUS" INT NOT NULL,
"GXSJ" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
CONSTRAINT "CONS13422015711" NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;
2、添加触发器到"GXSJ"这个字段上
CREATE OR REPLACE TRIGGER nasen_test_trigger
BEFORE UPDATE ON nasen_test
FOR EACH ROW
BEGIN
:new.GXSJ=CURRENT_TIMESTAMP();
END;
3、插入测试数据,并执行一个更新语句更新某一个字段测试然后看GXSJ字段是否取当前执行语句的时间即可
update nasen_test set STATUS =2 WHERE ID=1;
四、查看当前被锁堵塞的信息
SELECT SYSDATE STATTIME,DATEDIFF(SS,S1.LAST_SEND_TIME,SYSDATE) SS,
'被阻塞的信息' WT,S1.SESS_ID WT_SESS_ID,S1.SQL_TEXT WT_SQL_TEXT,S1.STATE WT_STATE,S1.TRX_ID WT_TRX_ID,
S1.USER_NAME WT_USER_NAME,S1.CLNT_IP WT_CLNT_IP,S1.APPNAME WT_APPNAME,S1.LAST_SEND_TIME WT_LAST_SEND_TIME,
'引起阻塞的信息' FM,S2.SESS_ID FM_SESS_ID,S2.SQL_TEXT FM_SQL_TEXT,S2.STATE FM_STATE,S2.TRX_ID FM_TRX_ID,
S2.USER_NAME FM_USER_NAME,S2.CLNT_IP FM_CLNT_IP,S2.APPNAME FM_APPNAME,S2.LAST_SEND_TIME FM_LAST_SEND_TIME
FROM V$SESSIONS S1,V$SESSIONS S2,V$TRXWAIT W
WHERE S1.TRX_ID=W.ID
AND S2.TRX_ID=W.WAIT_FOR_ID;
五、查询某个表的所有会话并杀掉解锁
select DISTINCT c.SESS_ID from v$lock a
left join sysobjects b on b.ID=a.TABLE_ID
left join v$sessions c on a.TRX_ID=c.TRX_ID
where name = '表名称';
sp_close_session(35451965760); #里面是数字就是sessionid
1、通过达梦客户端manager图像化工具进行设置
2、通过sql语句修改,相关语法参考以下sql(特别提醒:多个IP之间用逗号隔开,当已经存在某些开放IP的情况下再新增开放IP,一定要把之前的IP带上,否则将会丢失之前的开放IP信息):
alter user 用户名 allow_ip "允许登录的IP1",“允许登录的IP2”;
可通过以下系统表,查找出用户的开放IP有哪些?将以下sql查出的第二列添加到以上sql语句后面即可
select b.name,'"'||replace(a.allow_addr,'|','","')||'"' as allow_ip_list
from SYSUSERS a join SYSOBJECTS b on a.id=B.ID
where b.name='用户名'
达梦技术社区:https://eco.dameng.com