• 首先假设用户已经安装好达梦数据库了

数据迁移

新建表空间

在DM管理工具中的表空间文件夹右击=>新建表空间

  1. 在DM管理工具中的表空间文件夹右击=>新建表空间
    在这里插入图片描述
  2. 填写要创建的表空间名称. 文件路径不要点击那三个点,直接双击文件路径下空白的单元格就好.

新建用户

在这里插入图片描述

  1. 在DM管理工具中的用户下的管理用户文件夹右击=>新建用户
    在这里插入图片描述
  2. 表空间和索引表空间就选刚才创建好的表空间名称

数据迁移

打开DM数据迁移工具(桌面是找不到的,到开始=>全面里面去翻)
在这里插入图片描述

  1. 点这个下标,会弹出新建工程,点击新建工程
    在这里插入图片描述
  2. 点击刚才新建的工程里面有个迁移右击迁移=>新建迁移
    在这里插入图片描述
  3. 然后确认,下一步,我这边是MySQL就选MySQL.(根据具体情况选择)
    在这里插入图片描述
  4. 下一步后就是自己输入MySQL连接信息,达梦连接信息这边就跳过了.在下一步这边要选第二个,在下一步选择要迁移的库,表,在下一步,点击完成
    在这里插入图片描述
  5. 点击完成后等待一会会开始执行迁移任务.
    在这里插入图片描述
  6. 最后回到DM管理这里,模式右击刷新下就能看到导入过来的库和表了.(前提是上面的迁移任务米有失败…)
    在这里插入图片描述

项目改造

  • 项目示例以springBoot+mybatis为主
  1. pom.xml
        <!--引入达梦数据库连接依赖包-->
        <dependency>
            <groupId>com.dameng</groupId>
            <artifactId>DmJdbcDriver18</artifactId>
            <version>8.1.3.140</version>
        </dependency>
        <dependency>
            <groupId>com.dm</groupId>
            <artifactId>hibernate5</artifactId>
            <version>5.0</version>
            <scope>system</scope>
            <!--这个是包可以在达梦的安装路径里面找到
            默认在 C:\dmdbms\drivers\jdbc\dialect
            -->
            <systemPath>${project.basedir}/../libs/DmDialect-for-hibernate5.3.jar</systemPath>
                    <!-- https://mvnrepository.com/artifact/com.github.jsqlparser/jsqlparser -->
                    <!--
                    这个是下面拦截器用来解析SQL的
                    -->
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>4.9</version>
        </dependency>
        </dependency>
  1. 修改application.yml配置
  • 下面的具体配置以具体情况为准,主要参考url和hibernate.dialect两个参数
spring:
  datasource:
      datasource:
        master:
          username: test
          password: test112345@@1123
          url: jdbc:dm://localhost:5236/TEST?schema=TEST&compatibleMode=oracle
          driver-class-name: dm.jdbc.driver.DmDriver
  jpa:
    properties:
      hibernate.dialect: org.hibernate.dialect.DmDialect
    hibernate:
      ddl-auto: none
    show-sql: true
  1. 最重要的一点,修改现有项目中sql和达梦不兼容的问题.
    下面是mybatis拦截器代码,在答主这边的项目是可以适配了,也没去专门研究先用着在说.
    然后要注意的一点是,这个拦截器的执行顺序必须是在最前面的
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.*;
import org.apache.ibatis.executor.CachingExecutor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

@Intercepts({
        @Signature(type = Executor.class, method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
@Slf4j
public class SqlRewriteInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取当前的 StatementHandler
        Object[] args = invocation.getArgs();
        final MappedStatement mappedStatement = (MappedStatement) args[0];
        Object parameter = args[1];
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        if (boundSql != null) {
            String originalSql = boundSql.getSql();

            // 动态替换 SQL 的逻辑
            String modifiedSql = rewriteSql(originalSql);
            // 创建新的 MappedStatement
            MappedStatement newMs = newMappedStatement(mappedStatement, modifiedSql,args[1],boundSql);

            // 更新参数
            args[0] = newMs;
        }


        return invocation.proceed();

    }
    private MappedStatement newMappedStatement(MappedStatement ms, String newSql, Object parameter, BoundSql originalBoundSql) {
        // 使用原始的 ParameterMappings
        List<ParameterMapping> parameterMappings = originalBoundSql.getParameterMappings();

        // 创建新的 SqlSource,确保参数绑定正确
        SqlSource newSqlSource = new SqlSource() {
            @Override
            public BoundSql getBoundSql(Object parameterObject) {
                // 创建新的 BoundSql
                BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), newSql,
                        parameterMappings, parameterObject);

                try {
                    Field field = BoundSql.class.getDeclaredField("additionalParameters");
                    field.setAccessible(true);
                    Map<String, Object> additionalParams = (Map<String, Object>) field.get(originalBoundSql);
                    additionalParams.forEach(newBoundSql::setAdditionalParameter);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }

                return newBoundSql;
            }
        };

        // 构建新的 MappedStatement
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(),
                newSqlSource, ms.getSqlCommandType());
        builder.resource(ms.getResource())
                .fetchSize(ms.getFetchSize())
                .statementType(ms.getStatementType())
                .keyGenerator(ms.getKeyGenerator())
                .timeout(ms.getTimeout())
                .parameterMap(ms.getParameterMap()) // 保留原始参数映射
                .resultMaps(ms.getResultMaps())
                .cache(ms.getCache());
        return builder.build();
    }

    private StatementHandler getStatementHandler(Object target) {
        if (target instanceof StatementHandler) {
            return (StatementHandler) target;
        } else if (target instanceof CachingExecutor) {
            try {
                // 通过反射获取封装的 StatementHandler
                Field delegateField = CachingExecutor.class.getDeclaredField("delegate");
                delegateField.setAccessible(true);
                Executor delegate = (Executor) delegateField.get(target);
                if (delegate instanceof StatementHandler) {
                    return (StatementHandler) delegate;
                }
                // 进一步递归处理可能的代理对象
                return getStatementHandler(delegate);
            } catch (Exception e) {
                    log.error(e.getMessage(), e);
            }
        }
        return null;
    }

    private String rewriteSql(String originalSql) throws JSQLParserException {
        return addQuotesToFields(
                removeQuotesFromFields(
                        replaceEmptyQuotes(originalSql)
                )
        );
    }

    // 替换空双引号为空单引号
    private String replaceEmptyQuotes(String originalSql) {
        if (originalSql.contains("\"\"")) {
            return originalSql.replace("\"\"", "''");
        }
        return originalSql;
    }

    private String removeQuotesFromFields(String originalSql) {
        if (originalSql.contains("`")) {
            return originalSql.replace("`", "");
        }
        return originalSql;
    }

    private static class SelectVisitor extends SelectVisitorAdapter {
        @Override
        public void visit(PlainSelect plainSelect) {
            // 处理 SELECT 列表中的字段
            List<SelectItem<?>> selectItems = plainSelect.getSelectItems();
            if (selectItems!=null){
                for (SelectItem<?> item : selectItems) {
                    item.accept(new SelectItemVisitorImpl());
                }
            }

            FromItem fromItem = plainSelect.getFromItem();
            if (fromItem!=null){
                fromItem.accept(new FromItemVisitorAdapterImpl());
            }

            // 处理 ORDER BY 字段
            List<OrderByElement> orderByElements = plainSelect.getOrderByElements();
            if (orderByElements != null) {
                for (OrderByElement orderBy : orderByElements) {
                    orderBy.accept(new OrderByVisitorImpl());
                }
            }
        }
    }
    private static class SelectItemVisitorImpl implements SelectItemVisitor {

        @Override
        public void visit(SelectItem selectItem) {
            Expression expression = selectItem.getExpression();
            if (expression instanceof Column) {
                Column column = (Column) expression;
                String columnName = column.getColumnName();
                if (Objects.equals("\"\"",columnName)){
                    column.setColumnName("''");
                }else if (!columnName.startsWith("'") && !columnName.startsWith("\"")) {
                    column.setColumnName("\"" + columnName + "\"");
                }
            }
            if (selectItem.getAlias() != null) {
                String aliasName = selectItem.getAlias().getName();
                if (aliasName.startsWith("'")){
                    aliasName = aliasName.substring(1, aliasName.length() - 1);
                }
                if (!aliasName.startsWith("\"")) {
                    selectItem.getAlias().setName("\"" + aliasName + "\"");
                }
            }

        }
    }
    private static class OrderByVisitorImpl extends OrderByVisitorAdapter {
        @Override
        public void visit(OrderByElement orderBy) {
            Expression expression = orderBy.getExpression();
            if (expression instanceof Column) {
                Column column = (Column) expression;
                String columnName = column.getColumnName();
                if (!columnName.startsWith("'") && !columnName.startsWith("\"")) {
                    column.setColumnName("\"" + columnName + "\"");
                }
            }
        }
    }
    private static class FromItemVisitorAdapterImpl extends FromItemVisitorAdapter {
        @Override
        public void visit(ParenthesedSelect selectBody) {
            try{
                PlainSelect plainSelect = selectBody.getPlainSelect();
                if (plainSelect!=null){
                    plainSelect.accept(new SelectVisitor());
                }
            }catch (ClassCastException ignore){
                SetOperationList operationList = selectBody.getSetOperationList();
                if (operationList!=null){
                    operationList.getSelects().forEach(plainSelect -> {
                        plainSelect.accept(new SelectVisitor());
                    });
                }
            }
        }

        @Override
        public void visit(LateralSubSelect lateralSubSelect) {
        	log.info("LateralSubSelect  执行了");
        }
    }
    private String addQuotesToFields(String sql) throws JSQLParserException {
        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            if (statement instanceof Select) {
                Select select = (Select) statement;
                select.getSelectBody().accept(new SelectVisitor());
            }
            return statement.toString();
        }catch (Exception e){
            if (e.getMessage().contains("SAMPLE")) {
                String replace = sql.replace("sample", "tempSAVSLSFSA");
                String s = addQuotesToFields(replace);
                return s.replace("tempSAVSLSFSA", "sample");
            }else {
                log.error(String.format("SQL: %s 异常: %s",sql,e.getMessage()),e);
            }
        }
        return sql;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐