[数据库] MySQL适配达梦数据库

81 0
Honkers 2025-9-9 14:16:50 来自手机 | 显示全部楼层 |阅读模式

背景

因为国际局势的变化,国产化替代是如今重要的指导性思想,根据市场环境及公司的要求,需要对产品做达梦数据库的兼容。

1、环境与工具

首先需要部署一个达梦数据库的环境,可以到达梦官网去下载一个安装,我这边有专门的部门同事已经安装好测试环境,不必自己去安装。

使用达梦数据库时,可以用达梦自带的DM数据库管理工具,如果需要使用另外的数据库管理工具,可以下载安装SQLark白灵连接,目前可以免费使用。

c
1、添加达梦数据库驱动依赖

  1. <!--达梦数据库驱动-->
  2. <dependency>
  3. <groupId>com.dameng</groupId>
  4. <artifactId>DmJdbcDriver18</artifactId>
  5. <version>8.1.1.193</version>
  6. </dependency>
复制代码

2、修改配置文件
修改驱动依赖包为:spring.datasource.driver-class-name=dm.jdbc.driver.DmDriver
修改数据库连接url为:jdbc:dm://192.168.122.34:5236?schema=abc


如果不指定schema(即指定使用哪个数据库,在达梦指的是哪个schema),程序启动则会发生找不到对应的表的异常

3、添加方言包
如果程序使用了Hibernate JPA等对象映射框架,还需要引入方言,这里我们可以新建一个类,并进行配置

  1. package com.car.config;
  2. import org.hibernate.dialect.Dialect;
  3. import org.hibernate.dialect.function.VarArgsSQLFunction;
  4. import org.hibernate.type.StringType;
  5. import java.sql.Types;
  6. /**
  7. * @Author cwl
  8. * @Date 2025-02-08 16:27
  9. */
  10. public class DmDialect extends Dialect {
  11. public DmDialect() {
  12. super();
  13. registerColumnType(Types.BIT, "boolean");
  14. registerColumnType(Types.BIGINT, "bigint");
  15. registerColumnType(Types.SMALLINT, "smallint");
  16. registerColumnType(Types.TINYINT, "tinyint");
  17. registerColumnType(Types.INTEGER, "integer");
  18. registerColumnType(Types.CHAR, "char(1)");
  19. registerColumnType(Types.VARCHAR, "varchar($l)");
  20. registerColumnType(Types.FLOAT, "float");
  21. registerColumnType(Types.DOUBLE, "double");
  22. registerColumnType(Types.DATE, "date");
  23. registerColumnType(Types.TIME, "time");
  24. registerColumnType(Types.TIMESTAMP, "timestamp");
  25. registerColumnType(Types.BINARY, "binary");
  26. registerColumnType(Types.VARBINARY, "varbinary($l)");
  27. registerColumnType(Types.BLOB, "blob");
  28. registerColumnType(Types.CLOB, "clob");
  29. registerColumnType(Types.BOOLEAN, "boolean");
  30. registerFunction("concat", new VarArgsSQLFunction(StringType.INSTANCE, "", "||", ""));
  31. }
  32. }
复制代码
  1. spring.datasource.driver-class-name=dm.jdbc.driver.DmDriver
  2. spring.datasource.url=jdbc:dm://192.168.122.34:5236?schema=abc
  3. spring.datasource.username=SYSDBA
  4. spring.datasource.password=root
  5. #达梦方言包
  6. spring.jpa.database-platform=com.lancoo.car.config.DmDialect
复制代码

3、数据库脚本适配

原MySQL数据库中创建数据库的脚本,可以做一些修改以适配达梦数据库。
1、创建数据库语句调整
MySQL创建数据库语句

  1. CREATE DATABASE `name` ;
  2. USE `campuscar`;
复制代码

替换为以模式(schema)形式的创建数据库

  1. CREATE SCHEMA "name" ;
  2. ALTER SESSION SET CURRENT_SCHEMA = "name";/*设置当前会话*/
复制代码

2、去掉utf-8等字符的设置
3、表名的单引号改为双引号,如`tableName`改为"tableName"


4、去掉 ON UPDATE CURRENT_TIMESTAMP, 改为触发器实现
5、索引单独实现


6、tinyint\int\bigint 后面不带数字


7、设置自增主键

  1. # 从 1 开始,每次增加 1
  2. "id" int IDENTITY(1, 1) NOT NULL COMMENT '主键id',
复制代码

4、sql语句适配

1、 ifnull 名称改为 COALESCE
例如;ifnull(s.roomId,ao.roomId) as roomId 改为 COALESCE(s.roomId,ao.roomId) as roomId

2、 group_concat 方法需要修改
例如:group_concat(assetName) as applyAssetName 改为 LISTAGG(assetName, ', ') WITHIN GROUP (ORDER BY assetName) AS applyAssetName

5、可能会遇到的异常

1、达梦报错,发生变量空间溢出异常


原因是一次性插入了8838条记录,超过了在达梦数据库配置的缓存或者内存上限,可以对达梦数据库重新配置优化

也可以在程序中将超过1000个元素的列表拆开为小批量插入,设置1000为最大长度,拆开进行数据插入
这里可以新建一个工具类,使用Stream Api进行实现对数组的分割

  1. package com.car.util;
  2. import java.util.List;
  3. import java.util.stream.Collectors;
  4. import java.util.stream.IntStream;
  5. /**
  6. * @Author cwl
  7. * @Date 2025-02-10 16:08
  8. */
  9. public class CommonUtil {
  10. /**
  11. * 兼容达梦,列表数据插入之前先按默认最大1000分割列表
  12. * @param largeList
  13. * @param <T>
  14. * @return
  15. */
  16. public static <T> List<List<T>> DmInsertListSplit(List<T> largeList){
  17. return split(largeList, 1000);
  18. }
  19. /**
  20. *
  21. * @param largeList 原数组
  22. * @param chunkSize 目标数组长度
  23. * @return
  24. */
  25. public static <T> List<List<T>> split(List<T> largeList, int chunkSize){
  26. List<List<T>> smallLists = IntStream.range(0, largeList.size() / chunkSize + 1)
  27. .mapToObj(i -> largeList.subList(i * chunkSize, Math.min((i + 1) * chunkSize, largeList.size())))
  28. .collect(Collectors.toList());
  29. return smallLists;
  30. }
  31. }
复制代码

大量数据的列表分割成小列表后,成功将数据插入达梦数据库


2、设置了自增主键后,不能手动给主键赋值,如果需要手动赋值,需要先用命令打开限制


用命令打开限制

  1. # 若需手动赋值,需要先在当前环境打开
  2. SET IDENTITY_INSERT MyTable ON; -- 允许对自增列赋值
  3. # 数据插入后,建议关闭
  4. SET IDENTITY_INSERT MyTable OFF; -- 关闭对自增列的显式赋值
复制代码

3、给字段赋值空字符串时需要用单引号

4、sql脚本内有注释会导致 Cause: dm.jdbc.driver.DMException: 序列号无效,需要将注释删除

5、使用SQLark工具进行sql操作时,注意更新的sql操作需要加上事务提交 commit,否则更新不会提交,并且该事务一直未提交,会影响到其他事务的正常进行,达梦会报一些 jdbcType=null, 序列号无效之类的错误

  1. update parent set parName = 'chen' where stuUserId = 'S01001';
  2. # 如果没有隐式的事务自动提交,则此处需要显式地进行事务提交
  3. commit ;
复制代码

5、其他

(1)达梦不兼容 ON DUPLICATE KEY ,无法用此实现插入或更新的操作,例如

  1. @Insert({"<script>",
  2. "insert into "admin" (userId,userName)",
  3. " values",
  4. " (#{userId},#{userName})",
  5. " ON DUPLICATE KEY",
  6. " update userName = #{userName}",
  7. "</script>"})
复制代码

(2)admin是达梦的关键字,若有数据库表命名为admin时,需要加上 " ",如 “admin”

  1. @Update("update "admin" set userName = #{userName} where userId = #{userId}")
复制代码

(3)获取自增主键,statement = “SELECT IDENT_CURRENT(‘campuscar.gate’)”
在mysql中获取自增主键

  1. @Insert("insert into gate" +
  2. " (gateName,gateAddr,gateType)" +
  3. " values(#{param.gateName},#{param.gateAddr},#{param.gateType})")
  4. @SelectKey(statement = "select last_insert_id()", keyProperty = "param.id", before = false, resultType = int.class)
  5. int addGate(@Param("param") GateParam param);
复制代码

在达梦中获取自增主键

  1. @Insert("insert into gate" +
  2. " (gateName,gateAddr,gateType)" +
  3. " values(#{param.gateName},#{param.gateAddr},#{param.gateType})")
  4. @SelectKey(statement = "SELECT IDENT_CURRENT('campuscar.gate')",
  5. keyProperty = "param.id",
  6. before = false,
  7. resultType = int.class)
  8. int addGate(@Param("param") GateParam param);
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行