达梦数据库适配
·
- 首先假设用户已经安装好达梦数据库了
数据迁移
新建表空间

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

- 填写要创建的表空间名称. 文件路径不要点击那三个点,直接双击文件路径下空白的单元格就好.
新建用户

- 在DM管理工具中的用户下的管理用户文件夹右击=>新建用户

- 表空间和索引表空间就选刚才创建好的表空间名称
数据迁移
打开DM数据迁移工具(桌面是找不到的,到开始=>全面里面去翻)
- 点这个下标,会弹出新建工程,点击新建工程

- 点击刚才新建的工程里面有个迁移右击迁移=>新建迁移

- 然后确认,下一步,我这边是MySQL就选MySQL.(根据具体情况选择)

- 下一步后就是自己输入MySQL连接信息,达梦连接信息这边就跳过了.在下一步这边要选第二个,在下一步选择要迁移的库,表,在下一步,点击完成

- 点击完成后等待一会会开始执行迁移任务.

- 最后回到DM管理这里,模式右击刷新下就能看到导入过来的库和表了.(前提是上面的迁移任务米有失败…)

项目改造
- 项目示例以springBoot+mybatis为主
- 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>
- 修改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
- 最重要的一点,修改现有项目中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) {
}
}
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)