前段时间做过Mysql的项目适配达梦数据库,记录一下遇到的主要问题
一、配置修改
com.dameng DmJdbcDriver18 8.1.1.193
同样的,修改数据源中的驱动类名
spring.datasource.dynamic.datasource.master.driver-class-name=dm.jdbc.driver.DmDriverspring.datasource.dynamic.datasource.master.url=spring.datasource.dynamic.datasource.master.username=spring.datasource.dynamic.datasource.master.passWord=spring.datasource.dynamic.datasource.slave.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.dynamic.datasource.slave.driver-class-name=dm.jdbc.driver.DmDriverspring.datasource.dynamic.datasource.slave.url=spring.datasource.dynamic.datasource.slave.username=spring.datasource.dynamic.datasource.slave.password=
用的mybatis分页插件com.GitHub.pagehelper.PageHelper
,所以修改为oracle
pagehelper.helper-dialect=oracle
3.xml文件
我们项目需要同时兼容mysql和达梦,所以建了另一个application-dm.properties,用于使用达梦数据库时的配置。
对于存放sql的xml文件,复制一份用于达梦数据库使用,并修改配置
mybatis-plus.configuration.mapper-localtions=classpath:/mapper/dm**.xml
二、SQL适配
1.关键字列名
mysql中我们使用反引号来区分列名和关键字;但在达梦数据库中,使用双引号来区分。而如果创建实体类在注解@TableField中使用了反引号例如@TableField(`range`)
,这种我们改了的话,mysql就用不了,不改达梦就用不了。所以从代码入手,在启动时用反射修改值。
刚好mybatisPlus有个接口MybatisPlusPropertiesCustomizer
用于在读取properties之后进行一些自定义操作,我们可以利用这一点修改所有实体类中的@TableField的值。
@Slf4j@Configurationpublic class MybatisPlusConfig { @Bean public DmFieldCustomizer getDmFieldCustomizer() { return new DmFieldCustomizer(); } public static class DmFieldCustomizer implements MybatisPlusPropertiesCustomizer { public DmFieldCustomizer() { log.info("加载DmFieldCustomizer..."); } @SneakyThrows @Override public void customize(MybatisPlusProperties properties) { //使用达梦数据库 if (Arrays.toString(properties.getMapperLocations()).contains("dm")) { log.info("使用达梦数据库"); //实体类的class List> classList = new ArrayList<>(); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); //找到所有实体类的class Resource[] resources = resolver.getResources("classpath*:comentity*.class"); for (Resource res : resources) { // 先获取resource的元信息,然后获取class元信息,最后得到 class 全路径 String clsName = new SimpleMetadataReaderFactory().getMetadataReader(res).getClaSSMetadata().getClassName(); // 通过名称加载 Class> clazz = Class.forName(clsName); classList.add(clazz); } classList.forEach(e -> { List list = TableInfoHelper.getAllFields(e); list.forEach(field -> { TableField tableField = field.getAnnotation(TableField.class); String metaColName; if (tableField != null && StringUtils.isNotBlank(metaColName = tableField.value()) && metaColName.contains("`")) {String newColName = metaColName.replace("`", "\"");InvocationHandler invocationHandler = Proxy.getInvocationHandler(tableField);try { Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues"); memberValues.setAccessible(true); Map memberValuesMap = (Map) memberValues.get(invocationHandler); memberValuesMap.put("value", newColName); log.info("将实体类映射字段{}修改为{}", metaColName, newColName);} catch (NoSuchFieldException | IllegalAccessException exception) { throw new RuntimeException(exception);} } }); }); } else { log.info("使用mysql数据库"); } } }}
2.group by不能查询含多个值的列
例如 select * from user group by age;在mysql中可以通过select @@global.sql_mode;去掉sql_mode中ONLY_FULL_GROUP_BY
来实现查询。
在达梦数据库中,需要修改 dm.ini 的 compatible_mode 参数为 4。
三、验证mapper sql合法性
因为sql很多,不好测试,直接上去跑项目,可能跑几步就掉,得改了重新部署,所以利用easy-random
随机生成入参去跑sql,保证sql语法是正确的。
org.jeasy easy-random-core 4.3.0
import cn.hutool.core.exceptions.ExceptionUtil;import cn.hutool.core.io.FileUtil;import cn.hutool.core.lang.func.VoidFunc0;import cn.hutool.poi.excel.BigExcelWriter;import cn.hutool.poi.excel.ExcelUtil;import com.baomidou.mybatisplus.core.MybatisParameterHandler;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.apache.ibatis.executor.statement.StatementHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.ParameterMapping;import org.apache.ibatis.mapping.ParameterMode;import org.apache.ibatis.plugin.*;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.type.TypeHandlerReGIStry;import org.apache.poi.ss.SpreadsheetVersion;import org.jeasy.random.EasyRandom;import org.jeasy.random.EasyRandomParameters;import org.jeasy.random.randomizers.AbstractRandomizer;import org.springframework.aop.framework.AopProxyUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.Ordered;import org.springframework.core.ResolvableType;import org.springframework.stereotype.Component;import org.springframework.transaction.TransactionStatus;import org.springframework.transaction.support.TransactionCallbackWithoutResult;import org.springframework.transaction.support.TransactionTemplate;import org.springframework.util.ReflectionUtils;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.math.BigDecimal;import java.sql.Statement;import java.text.SimpleDateFORMat;import java.util.*;import java.util.regex.Matcher;import java.util.stream.Collectors;import java.util.stream.IntStream;@Slf4j@Componentpublic class SimpleMapperTest { private static final String OUT_PATH = "D:/SQL执行结果.xlsx"; private static final String PACKAGE_KEYWORD = "my_package"; private static final String SQL_KEY = "mybatis_sql"; public static final ThreadLocal
执行完后会生成excel表格,能看到sql是否执行成功,能拿到报错的mapper方法,但是拿不到执行报错的sql。
来源地址:https://blog.csdn.net/qq_40800602/article/details/129297871
0