项目适配达梦数据库遇到的一些坑

6,520 阅读8分钟

安装达梦数据库

linux安装手册:eco.dameng.com/document/dm…

项目对接达梦数据库

Flyway不支持达梦

Flyway不支持达梦,如果想要Flyway支持达梦,需要创建达梦Database,就得对Flyway进行二次开发。

具体步骤可以参考:blog.csdn.net/u012440725/…

MySQL与达梦不兼容的地方

MySQL与达梦数据库在语法和类型上存在不兼容的地方,在迁移的过程中发现如下问题:

  1. MySQL在创建表的过程中指定了

    ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4
    

    都需要把它去掉

  2. MySQL在指定表名,字段名的时候,可以添加tablename,columnname,迁移到达梦数据库的时候需要把这个``去掉。

  3. MySQL在创建表的过程中可以创建KEY,但是在达梦数据库里,需要使用CREATE INDEX语句创建。例如: MySQL原始语句:

    CREATE TABLE `user`
    (
        `id`             bigint NOT NULL,
        `description`    varchar(255) DEFAULT NULL,
        `dept_id` bigint       DEFAULT NULL,
        PRIMARY KEY (`id`),
        KEY `FKoecs3fe5jj262ku2lnvncu2bg` (`dept_id`),   -- MySQL这这里创建了普通索引
        CONSTRAINT `FKoecs3fe5jj262ku2lnvncu2bg` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4;
    

    上面的代码在达梦数据库里执行会报错,需要将SQL改为

    CREATE TABLE user   -- 去掉``
    (
        id bigint NOT NULL, -- 去掉``
        description varchar(255) DEFAULT NULL,
        dept_id bigint DEFAULT NULL,
        PRIMARY KEY (id),
                             -- 去掉KEY `FKoecs3fe5jj262ku2lnvncu2bg` (`rtidbconfig_id`)
        CONSTRAINT FKoecs3fe5jj262ku2lnvncu2bg FOREIGN KEY (dept_id) REFERENCES dept (id)
    ); -- 去掉ENGINE = InnoDB DEFAULT CHARSET = utf8mb4
    -- 创建索引
    CREATE INDEX FKoecs3fe5jj262ku2lnvncu2bg ON user(dept_id);
    
  4. MySQL在建表的时候创建UNIQUE INDEX,可以用UNIQUE KEY关键词来创建,但是达梦数据库不支持,可以通过两种方式来实现。例如 MySQL原始语句:

    CREATE TABLE `dept`
    (
        `id` bigint NOT NULL,
        `code` varchar(50) NOT NULL,
        UNIQUE KEY `UK_khxe6t3tbtfjnn9b7piuiiedj` (`code`) -- 使用的是UNIQUE KEY
        PRIMARY KEY (id)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4;
    

    达梦创建unique index的语句如下: 第一种方式,在创建表的时候就可以创建unique index

    CREATE TABLE dept
    (
        id bigint NOT NULL,
        code varchar(50) NOT NULL,
        constraint UK_khxe6t3tbtfjnn9b7piuiiedj unique(code) -- 使用constraint <unique index name> unique <column name>的方式
        PRIMARY KEY (id)
    );
    

    第二种方式,先建表在创建unique index

    CREATE TABLE dept
    (
        id bigint NOT NULL,
        code varchar(50) NOT NULL,
        PRIMARY KEY (id)
    );
    CREATE UNIQUE INDEX UK_khxe6t3tbtfjnn9b7piuiiedj ON dept(code);
    
  5. 达梦在创建外键的时候,需要保证关联的表已经存在,例如上述3里的demo,在创建user表的时候指定了外键,关联了dept,就需要先保证dept这张表已经存在。

  6. 如果在执行达梦SQL的时候,SQL语句里带有关键词,可以给关键词加上双引号,不过最好建议改成非关键词。例如:

    CREATE TABLE keywords
    (
        id bigint NOT NULL,
        "COMMENT" text null,     -- COMMENT在达梦数据库里是关键词,需要用""
        PRIMARY KEY (id)
    );
    

    达梦数据库关键词可以参考:eco.dameng.com/document/dm…

  7. MySQL创建表的时候,可以给update_time字段加上ON UPDATE CURRENT_TIMESTAMP,但是达梦不支持。例如: MySQL原始语句

    CREATE TABLE IF NOT EXISTS `update_time_test`
    (
        `id`               int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
        `name`             varchar(32)      NOT NULL DEFAULT '' COMMENT 'schema名称',
        `create_time`      datetime                  DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
        `creator`          varchar(255)     NOT NULL DEFAULT '' COMMENT '创建人id',
        `last_modify_time` datetime                  DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',  --这里使用ON UPDATE CURRENT_TIMESTAMP
        `status`           int(4) unsigned           DEFAULT '1' COMMENT '状态 0:草稿,1:正常',
        `deleted`          int(4) unsigned           DEFAULT '0' COMMENT '删除状态 0:未删除,1:已删除',
        PRIMARY KEY (`id`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4;
    

    达梦需要对应修改成:

    CREATE TABLE IF NOT EXISTS update_time_test
    (
        id int NOT NULL AUTO_INCREMENT COMMENT '自增主键',
        name varchar(32) NOT NULL DEFAULT '' COMMENT 'schema名称',
        create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
        creator varchar(255) NOT NULL DEFAULT '' COMMENT '创建人id',
        last_modify_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '最后修改时间',
        status int DEFAULT '1' COMMENT '状态 0:草稿,1:正常',
        deleted int DEFAULT '0' COMMENT '删除状态 0:未删除,1:已删除',
        PRIMARY KEY (id)
    );
    ​
    ​
    -- 如果想要实现类似ON UPDATE CURRENT_TIMESTAMP的功能,可以创建触发器来实现。
    
  8. IDP在MySQL数据库里有Hibernate_Sequence这张表,但是在达梦数据库里需要将表转化为sequence(也可以不手动转,在启动jpa的时候,会自动帮忙创建,看具体需求),语法如下:

    create sequence hibernate_sequence start with 1 increment by 1
    
  9. MySQL修改字段,使用change的语法跟达梦的不兼容,例如: 第一种:重命名字段

    ALTER TABLE `tableA`
        CHANGE colA colB VARCHAR(255) NULL;  -- 将tableA的colA重命名为colB,并修改类型为VARCHAR(255) NULL
    

    对应的达梦SQL语句如下:

    ALTER TABLE tableA rename column colA to colB;
    ALTER TABLE tableA modify colB VARCHAR(255) NULL;
    

    第二种:直接修改字段类型

    ALTER TABLE tableB
        CHANGE COLUMN colC colC VARCHAR(16) null;
    

    对应的达梦SQL语句如下:

    ALTER TABLE tableB
        modify colC VARCHAR(16) null;
    
  10. MySQL可以一条SQL删除多张表,达梦则需要一个个执行 MySQL原始语句

    drop table tableA, tableB, tableC;
    

    达梦需要对应修改成:

    drop table tableA;
    drop table tableB;
    drop table tableC;
    
  11. MySQL原始数据类型为bit(1),或者boolean,再插入值的时候,可以插入true, false。但是达梦只能插入1,0,其中1表示true,0表示false。例如: MySQL原始插入语句:

    INSERT INTO `tableA` (`id`, `active`, `create_time`, `creator_id`, `deleted`, `level`,
                                  `name`, `parent_id`,
                                  `update_time`, `updated_by`)
    VALUES (1, true, '2021-07-24 18:28:09.000000', 3, false, 1, '总部', 0, '2021-07-24 18:28:09.000000',
            'admin'); -- active的值为true
    

    达梦需要对应修改成:

    INSERT INTO irm_department (id, active, create_time, creator_id, deleted, level, name, parent_id, update_time, updated_by) VALUES (1, 1, cast('2021-07-24 18:28:09' as datetime(6)), 3, 0, 1, '总部', 0,cast('2021-07-24 18:28:09' as datetime(6)), 'admin'); -- active的值为1
    
  12. MySQL支持Replace Into语法,但达梦不支持,可以使用delete + insert的方式或者merge into的语法来实现。例如

    MySQL原始语句

    ​
    REPLACE INTO menu (id, bpid, code, icon, mpid, name, route, scene_type, target, top)
    VALUES ('09060000', '09000000', 'testt', null, '09000000', 'test',
            'test', '6,7', null, false);
    

    达梦需要对应修改成:

    delete from menu where id = '09060000';
    INSERT
    INTO
        menu (id,
        bpid,
        code,
        icon,
        mpid,
        name,
        route,
        scene_type,
        target,
        "TOP")
    VALUES ('09060000',
    '09000000',
    'test',
    null,
    '09000000',
    'test',
    'test',
    '6,7',
    null,
    0);
    
  13. 数据类型不兼容

    MySQL数据类型达梦数据类型备注
    longtext,textclob
    bit(1)bit数字类型,MySQL bit类型可以指定长度,达梦不可以
    int(11)int数字类型,MySQL int类型可以指定长度,达梦不可以
    longblob,mediumblob,tinyblobblob
    tinyint(1)tinyint数字类型,MySQL tinyint类型可以指定长度,达梦不可以

    MySQL在指定int类型的时候,还有指定是否有符号,unsigned,达梦则不需要指定,例如: MySQL原始语句

    CREATE TABLE IF NOT EXISTS `tableB`
    (
        `id`          int unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',  -- 这里指定了unsigned
        `code`        varchar(64)  NOT NULL DEFAULT '',
        `name`        varchar(64)  NOT NULL DEFAULT '',
        `description` varchar(64)  NOT NULL DEFAULT '',
        `type`        varchar(32)  NOT NULL DEFAULT '',
        PRIMARY KEY (`id`)
    );
    

    达梦需要对应修改成:

    CREATE TABLE IF NOT EXISTS tableB
    (
        id int NOT NULL AUTO_INCREMENT COMMENT '自增主键', -- 去掉unsigned
        code varchar(64) NOT NULL DEFAULT '',
        name varchar(64) NOT NULL DEFAULT '',
        description varchar(64) NOT NULL DEFAULT '',
        type varchar(32) NOT NULL DEFAULT '',
        PRIMARY KEY (id)
    );
    
  14. 还有一些函数的区别,可以参考www.178syedu.com/docs/4d4ddc…

JPA整合达梦数据库

  1. 添加驱动包和达梦数据库的方言包 驱动包需要从达梦数据库的安装路径下获取,例如,我们已经将DM安装到了/dm8这个目录下,那么驱动包就在/dm8/drivers/jdbc目录下。 由于hibernate官方并没有支持达梦数据库的方言,所以也需要添加方言包,路径在/dm8/drivers/jdbc/dialect目录下。 我们数据库安装的版本是v8,所以对应驱动包就选择DmJdbcDriver18.jar。hibernate-core的版本是5.3.15.Final,所以对应的驱动包就选择DmDialect-for-hibernate5.3.jar。 image-20230206004223334 将这两个jar上传到公司的maven的仓库里,供方便下载。 之后使用gradle,或者maven引用依赖,例如

    damengVersion = '8.1.2.142'
    hibernateVersion = '5.3.15.Final'
    dmDialectHibernateVersion = '8.1.2.141'
    springbootVersion = '2.5.4'libs_damengConnector = [group: 'com.dameng', name: 'DmJdbcDriver8', version: damengVersion]
    libs_hibernateCore = [group: 'org.hibernate', name: 'hibernate-core', version: hibernateVersion]
    libs_dmDialectHibernate = [group: 'com.dameng', name: 'DmDialect-for-hibernate5.3', version: dmDialectHibernateVersion]
    ​
    libs_springbootJpa = [group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: springbootVersion]
    libs_springbootWeb = [group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springbootVersion]
    
  2. 修改application.yaml。将driverClassName改成dm.jdbc.driver.DmDriver,方言选择 org.hibernate.dialect.DmDialect

    
    spring:
      datasource:
        url: jdbc:dm://192.168.180.128:5236
        username: shawn
        password: shawn123456789
        driver-class-name: dm.jdbc.driver.DmDriver
    
      jpa:
        properties:
          hibernate:
            dialect: org.hibernate.dialect.DmDialect
            show_sql: true
            format_sql: true
            default_schema: IDP
        hibernate:
          ddl-auto: update
    
  3. entity里如果有关键词,执行jpa方法则会报错,有两种方式可以解决 第一种方式:使用@Column(name = ""comment""),加上双引号 第二种就是:使用@Column(name = "recode_comment"),将数据库里的字段comment改成recode_comment。

  4. jpa可以通过@GeneratedValue注解来选择id生成的策略,默认是AUTO。如果是AUTO,就会默认使用数据库内部推荐的id生成策略。MySQL就只有auto_increment方式,但是达梦支持sequence和auto_increment两种方式,另外,sequence的优先级会更高,所以如果@GeneratedValue指定的AUTO,在达梦数据库里就会选择使用全局的SEQUENCE来生成id。 建议@GeneratedValue按照实际需求指定具体的生成策略。

  5. 最后,需要注意的是,建议使用安装达梦数据库下的Jdbc驱动包和方言包,可能兼容性比较差。旧版本的不一定能在新版本里运行。