SpringBoot连接达梦与MySQL多数据源配置实战及避坑指南
发布时间:2026/9/10 1:21:52 锦皓数字建站

前阵子做一个信创项目业务系统要从Oracle迁到达梦同时还要保留一个MySQL库做用户中心的存量数据两边实时互通。项目组里有个同事光是折腾SpringBoot连接达梦多数据源就卡了两天一会儿驱动类找不到一会儿表或视图不存在后来还踩了一个序列的坑最后我发现问题全集中在几个“约定俗成”但没人明说的细节上。这篇就把整个配置过程、使用姿势和常见错误完整梳理一遍给你一条可以直接走通的路。1. 场景拆解与多数据源方案选型1.1 为什么业务里会同时出现“达梦MySQL”这种多数据源结构很多人一听到多数据源就头大但实际项目中真的非常常见。拿我那个项目举例系统本身是SpringBoot单体应用主库是达梦8国产化要求但历史订单和用户资料挂在另一个MySQL实例上。两个库之间不做强同步只是业务服务需要同时读写两边。这种场景下你不可能把MySQL的数据全部迁移进达梦迁移成本太高也没必要更不可能写几套独立服务再走RPC去互相调用数据一致性反而更难控制。所以最务实的方案就是一个SpringBoot应用同时挂两个数据源代码里根据业务方法动态选择走哪个库。这就是“多数据源”最典型的落地场景。类似的还有一个达梦主库做交易一个达梦从库做报表查询或者开发阶段同时连达梦测试库和本地MySQL库再或者老系统是SQLServer新系统是达梦需要做数据同步比对——这些都是多数据源。1.2 三种主流实现方式怎么选做多数据源网上方案看着多实际上不外乎三种路子方案实现成本事务控制维护难度适合场景手动创建多个DataSource JdbcTemplate低基本靠手写高代码里到处传参只做临时查询、工具类AbstractRoutingDataSource 自定义注解 AOP中需要自己处理中要写不少样板代码团队规模小、规则简单dynamic-datasource-spring-boot-starter低开箱即用原生支持低生态成熟绝大多数业务项目我强烈建议直接用第三种也就是MyBatis-Plus官方团队出的dynamic-datasource-spring-boot-starter。原因很简单人家把动态切换、事务回滚、多数据源下的事务隔离这些最坑的部分都封装好了你只需要用DS注解指定数据源剩下的框架帮你搞定。我第一次用的时候也担心“封装太黑盒”但实际源码逻辑很清晰而且社区用户量大你踩过的坑大概率别人也踩过问题基本都能搜到。如果你坚持用AbstractRoutingDataSource手写也可以但请做好心理准备至少要处理数据源注册、动态切换的线程隔离、嵌套切换的恢复逻辑以及分布式事务。这些细节一旦不注意线上会出现“数据写到A库去了”“事务只回滚了一半”这类难以排查的问题。如果项目工期紧别折腾自己。2. 达梦数据库连接前必须搞清楚的几个知识点2.1 JDBC驱动、端口与URL格式达梦8的JDBC驱动和MySQL、Oracle不太一样它的jar包在Maven中央仓库是没有的需要从达梦安装目录里拷出来自己install到本地Maven仓库。安装达梦数据库后驱动文件一般在数据库安装目录的drivers/jdbc/下面常见的文件名是DmJdbcDriver18.jar对应JDK1.8及以上或DmJdbcDriver8.jar对应JDK1.6及以上。驱动类名是dm.jdbc.driver.DmDriver注意大小写不能错。连接URL的格式jdbc:dm://IP:端口 jdbc:dm://IP:端口?schema模式名达梦默认端口是5236不是1521也不是3306。很多人第一次连达梦习惯性敲localhost:1521结果报连接超时其实端口改一下就通了。如果你的达梦实例有多个模式Schema建议在URL上直接指定schema避免后面对话里反复写用户名.表名。2.2 大小写敏感达梦和MySQL最大的思维差异这一条可以说是新手翻车第一原因。达梦在默认配置下CREATE TABLE的时候如果表名和字段名不加双引号会统一转成大写存储。而MySQL默认是区分大小写策略比较宽松所以很多人从MySQL切到达梦后写SQL直接用小写表名结果报“表或视图不存在”。举个例子如果你在达梦里执行的是CREATE TABLE user_info (id INT, user_name VARCHAR(50));达梦实际存储的表名是USER_INFO字段是ID、USER_NAME。你再用MyBatis-Plus的自动生成的SQL去查user_info默认不加引号的情况下达梦会把SQL中的小写标识符也转成大写去匹配所以一般还能命中。但一旦你用了双引号包小写名——比如SELECT * FROM user_info——那就会去查一个小写的user_info表而数据库里没有直接报错。MySQL迁到达梦后最稳妥的做法是建表时统一用大写代码里也统一用大写。如果既有代码是大写习惯那就没这个问题如果代码里全是小写建议在建库时把达梦的大小写敏感参数配置好或者在迁移时统一处理列名。这个坑我在项目和DBeaver客户端里都踩过排查了半天最后发现就是大小写对不上。2.3 序列、自增主键和分页习惯要改达梦兼容Oracle语法所以MySQL里常用的AUTO_INCREMENT自增主键在达梦里默认并不支持除非设置兼容MySQL模式。达梦的自增主键一般用IDENTITY列或者用序列触发器实现。如果你从MySQL迁移数据表过来原来的自增主键列到达梦后变成普通列插入数据时不处理主键就会报非空违规。此外MyBatis-Plus的自动填充和ID生成策略在达梦下建议显式配置成INPUT或ASSIGN_ID别指望数据库自动生成。分页方面达梦的默认分页写法和Oracle类似可以用ROWNUM但如果你把达梦配置成了MySQL兼容模式也可以用LIMIT。MyBatis-Plus的分页插件需要指定数据库类型为DM不然分页SQL可能生成不对。3. 完整实操SpringBoot项目接入达梦多数据源3.1 引入依赖注意版本兼容性我用的是SpringBoot 2.7.x MyBatis-Plus 3.5.x dynamic-datasource 3.5.2这套组合很稳定。如果你用的是SpringBoot 3.x那要选dynamic-datasource 3.6.0以上版本而且要注意javax包改成jakarta的问题——这在SpringBoot 3.x里是常规操作了。Maven依赖如下!-- 动态数据源核心 -- dependency groupIdcom.baomidou/groupId artifactIddynamic-datasource-spring-boot-starter/artifactId version3.5.2/version /dependency !-- MyBatis-Plus 针对SpringBoot的启动器 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency !-- 达梦驱动注意是本地安装的jar包坐标自己定 -- dependency groupIdcom.dameng/groupId artifactIdDmJdbcDriver18/artifactId version8.1.2.192/version /dependency关于达梦驱动install到本地仓库用maven命令mvn install:install-file -DfileDmJdbcDriver18.jar -DgroupIdcom.dameng -DartifactIdDmJdbcDriver18 -Dversion8.1.2.192 -Dpackagingjar如果你公司有Nexus私服建议直接传到私服这样整个团队不用每个人都装一遍。3.2 application.yml 配置主从数据源都要写完整这是整个配置过程最核心的部分。我们定义两个数据源一个是达梦dm一个是MySQLmysql把达梦设为主数据源。spring: datasource: dynamic: primary: dm strict: false lazy: true datasource: dm: driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://192.168.10.20:5236?schemaTJDBcompatibleModeoracle username: TJDB password: tjdb123 mysql: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.10.30:3306/user_center?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root123几个关键点说下primary: dm表示默认走达梦只有加了DS(mysql)的方法才走MySQL。这个设计很有用因为主业务表都在达梦大多数Mapper方法不用加注解。strict: false表示如果找不到指定的数据源就回退到主数据源不会直接报错。建议开发环境先设成false方便排查。生产环境我一般设成true避免代码写错数据源名称导致默默走了主库出事故。lazy: true表示懒加载数据源应用启动时不主动校验所有数据源连接只有第一次用到才创建。如果某个从库临时不可用主服务依然能正常启动这个对生产环境很友好。有同事问我这个dynamic数据源配置下SpringBoot自带的DataSourceAutoConfiguration会不会冲突答案是dynamic-datasource启动器会自动处理无需手动排除。但如果你项目里还引了其他数据源相关starter出现冲突时可以试试在主启动类上加SpringBootApplication(exclude {DataSourceAutoConfiguration.class})不过一般情况下不需要加了这个反而会引入其他问题。3.3 代码目录结构与DS注解使用配置写好后咱们在代码里怎么用核心就一个注解DS。建议的Mapper或者Service目录结构com.example.project ├── controller ├── service │ ├── UserService.java │ └── OrderService.java ├── mapper │ ├── UserMapper.java // 操作MySQL用户中心 │ └── OrderMapper.java // 操作达梦订单表在Service实现类上加注解Service DS(dm) public class OrderServiceImpl implements OrderService { Autowired private OrderMapper orderMapper; Override public ListOrder listOrders() { return orderMapper.selectList(null); } }另一个Service切到MySQLService DS(mysql) public class UserServiceImpl implements UserService { Autowired private UserMapper userMapper; Override public User findByUserId(Long userId) { return userMapper.selectById(userId); } }如果你有的方法要切不同的数据源可以把注解写在方法上方法上的优先级高于类上。比如Service DS(dm) public class MixedServiceImpl implements MixedService { Override DS(mysql) public User getUserFromMysql(Long id) { return userMapper.selectById(id); } Override public Order getOrderFromDm(Long id) { return orderMapper.selectById(id); } }3.4 事务场景下的坑Transactional会让DS“失灵”这个坑我琢磨了很久才搞明白。dynamic-datasource的DS切换数据源本质上是在每次数据库操作前通过AOP动态设置当前线程的数据源key。但Spring的Transactional是在方法进入前就开启了事务事务管理器会提前从DataSourceUtils里拿连接并且在整个事务期间把这个连接绑定到当前线程。所以如果你在一个方法上同时加了Transactional和DS(mysql)虽然DS会去切数据源但事务已经基于原来的连接开启了实际执行的还是主库连接DS就失效了。我遇到的现象是一个统计方法标了Transactional里面调用了多个Mapper其中有个Mapper是走MySQL的但查询出来的数据全是达梦里的半天没发现问题。排查时单独调那个Mapper又是对的问题就出在事务与数据源切换的顺序上。解决办法有三种如果切换数据源的方法不需要事务直接去掉Transactional。把不同数据源的操作拆到不同的Service方法里通过Transactional的传播行为控制比如在MySQL的Service方法上单独加事务。使用DSTransactional注解这是dynamic-datasource提供的分布式事务注解可以跨数据源做本地事务协调基于本地消息表思路但它不是标准意义上的强一致分布式事务业务上要考虑可回滚性。提示同一个方法里既开了事务又切数据源这个组合属于高危操作不是每次都会报错而是“看似正常实则错误”。我建议在代码评审时把这个列为重点检查项。4. 常见错误与排查记录4.1 “driver not found” / 无法加载驱动类这个报错十有八九是达梦驱动jar没有打进来。可能性有几种没执行mvn install把达梦驱动装进本地仓库直接编译报找不到依赖。装了但SpringBoot打包时没包含驱动排查时先看打出来的jar里有没有dm.jdbc.driver.DmDriver这个类。版本不匹配比如JDK17环境用了DmJdbcDriver8.jar有些旧版驱动反射会失败。此时应换用DmJdbcDriver18.jar。4.2 “表或视图不存在” / “无效的列名”前面提到的大小写问题占一半另一半是schema模式不对。达梦里的“用户”和“模式”是绑定的一个用户默认对应一个同名模式。你连接数据库用的账号是TJDB那你默认看到的就是TJDB模式下的表。如果你要访问另一模式OTHER下的表要么在SQL里写OTHER.TABLE_NAME要么在URL指定schema参数。MyBatis-Plus生成SQL不会自动加模式前缀所以如果表不在默认模式下就会报“表或视图不存在”。排查顺序建议先用DBeaver或达梦自带的Manager工具连接数据库确认表和字段的实际存储名称。确认URL里schema参数和代码里Mapper对应的表名是否匹配。确认账号是否有查询该表的权限。另外如果SQL里用了达梦的保留字做字段名比如comment、level、desc也会报“无效的列名”这种需要给字段名加双引号处理或者直接改字段名。4.3 达梦连接报错 [-6602] 或者连接超时这个错误代码很典型。达梦连接失败有一类常见码是[-6602]含义通常是网络通信故障或连接无法建立。排查步骤先在本机用DBeaver或者达梦Manager试连一下排除账号密码错误。用命令行测端口连通性telnet 192.168.10.20 5236端口不通就检查达梦服务是否启动。如果服务在其他机器上检查服务器防火墙是否放行5236端口。在达梦服务器上执行systemctl status DmServiceDMSERVER服务名可能不同确认实例状态。我在麒麟系统上就遇到过这个问题达梦客户端装好了但服务端5236端口没开DBeaver连不上SpringBoot也连不上耗了半天最后发现是安全策略把端口拦了。这个也算达梦比较常见的“客户端能装但连不上”场景先测端口永远排在第一位。4.4 连接池初始化失败 / HikariCP超时SpringBoot默认用HikariCP连接池连接达梦时如果初始化失败报错可能类似HikariPool-1 - Exception during pool initialization。原因多是URL不对、账号密码错、驱动类不对。一个容易忽略的配置项是connection-test-query。HikariCP默认会发一条SELECT 1来测试连接有效性达梦是支持SELECT 1的一般没问题。但如果你的达梦版本较老或者配置了奇怪的schema测试SQL可能失败此时可以显示配置spring: datasource: dynamic: datasource: dm: hikari: connection-test-query: SELECT 1 FROM DUAL4.5 MyBatis-Plus分页插件报错SQL生成不对如果你的MyBatis-Plus分页插件配置不指定达梦方言分页SQL会按默认的MySQL方言生成LIMIT达梦如果是Oracle兼容模式就会报错。正确配置方式Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.DM)); return interceptor; } }DbType.DM是MyBatis-Plus直接支持的数据库类型指定后分页SQL会生成达梦兼容的写法底层是使用ROWNUM或者达梦的TOP语法不用你手写。分页插件不生效的另一个现象是通过selectPage方法查数据时total一直为0或者查出的结果不带分页SQL。这种情况先看mapper接口是否继承了BaseMapper再看分页插件是否注册成功最后看控制台打印的SQL里有没有LIMIT或ROWNUM关键字。4.6 序列不存在或者nextval语法问题如果你在达梦里用了序列比如SEQ_USER_ID.NEXTVAL一定要注意大小写。达梦默认将未加引号的标识符转大写如果你建序列时用的是CREATE SEQUENCE seq_user_id START WITH 1 INCREMENT BY 1;那实际的序列名是SEQ_USER_ID。那么在MyBatis的XML里写selectKey keyPropertyid resultTypejava.lang.Long orderBEFORE SELECT SEQ_USER_ID.NEXTVAL FROM DUAL /selectKey如果你写的是seq_user_id.nextval且没有加双引号达梦统一转大写一般也能执行成功。但如果在SQL里用了seq_user_id大小写敏感模式下就找不到序列了。用MyBatis-Plus时也可以在实体类主键上指定TableId(value ID, type IdType.INPUT) private Long id;这样插入前需要手动设置主键或者通过自定义的元对象处理器来填充序列值。实战中我更推荐用数据库序列触发器方式代码里设置IdType.INPUT插入时让数据库自己处理主键。4.7 Kettle、DBeaver连接达梦的小经验虽然这是SpringBoot配置博文但排查问题时候免不了要用客户端工具连达梦。Kettle连接达梦时需要手动选择达梦驱动连接URL格式和SpringBoot里一致。注意Kettle8/9版本对达梦驱动的兼容性如果加载不到驱动把DmJdbcDriver18.jar放到Kettle的lib目录下即可。DBeaver连接达梦相对简单新建连接时选“达梦”输入地址端口账号密码就行。但DBeaver社区版有时识别不了达梦的某些数据类型比如CLOB显示异常这不影响SpringBoot应用只是客户端看数据时不太方便。用达梦自带的Manager工具Windows端体验最完整但Linux服务器上就靠命令行工具disql了。5. 多数据源配置后的日常开发经验配置走通之后日常开发还有一些细节点这里集中说下。首先明确数据源边界。我建议一开始就在项目文档里规定哪个Service操作哪个库不要把DS注解散落到Mapper层。实际经验是DS注解放在Service实现类上最合理因为一个Service通常对应一个业务域数据源边界清晰。如果放在Mapper接口上Controller调多个Mapper时数据源切换频繁很容易出现方法间调用时上下文丢失的问题。其次多数据源下的代码生成器策略。MyBatis-Plus代码生成器默认生成的实体类只包含表结构字段达梦的部分字段类型可能映射不准确比如NUMBER类型映射成BigDecimal而不是Long这个在生成后要人工审一遍。别指望代码生成器一次到位Mapper XML里的自定义SQL仍需要手写。再就是监控。多数据源场景下出问题时第一件事就是确认当前线程走的是哪个数据源。dynamic-datasource提供了DynamicContextHolder.push/poll/peek方法可以在代码里临时打印String currentDs DynamicContextHolder.peek(); log.info(当前数据源: {}, currentDs);我在排查类似问题的时候会在进入MQ消费方法、定时任务这类没有显式指定数据源的入口时打印当前数据源key避免“我以为走MySQL实际走了达梦”这种迷惑行为。最后说一说定时任务和异步线程。Scheduled定时任务和Async异步方法里数据源切换是基于当前线程的ThreadLocal如果异步线程池里有线程复用上一个任务设置的数据源可能会泄漏到下一个任务。dynamic-datasource解决了一部分但我的建议是在定时任务方法首行显式声明DS(dm)确保这个任务无论被哪个线程执行都有一个确定的数据源上下文。6. 我踩过的坑替你提前避掉最后一个部分不列代码了纯粹分享几个实战中特别容易让人抓狂的细节你遇到了能省好几个小时。第一个是达梦驱动的版本和JDK版本匹配问题。有些项目用的是JDK1.8但驱动用了旧版DmJdbcDriver8.jar接口反射偶尔会报NoSuchMethodError这种错误表面上看是代码问题实际是驱动太旧。建议新项目直接用DmJdbcDriver18.jarJDK8及以上都能跑。第二个是“达梦多数据源下实体类的主键策略没改导致插入报错”。很多人从MySQL迁移过来实体类主键写的IdType.AUTO这招在达梦直接失效。我上面建议改成IdType.INPUT或ASSIGN_ID后再用序列填充主键这样两种库下插入都不出错。第三个是SpringBoot版本太高带来的问题。如果你用的SpringBoot 3.2.xdynamic-datasource需要升级到3.6.x不然后面切换数据源时可能遇到BeanNotOfRequiredTypeException。我在测试环境就遇到过SpringBoot 3.0.2配dynamic-datasource 3.5.2启动不报错但一运行就报HikariDataSource cannot be cast to com.zaxxer.hikari.HikariDataSource网上搜了一圈才发现是版本兼容问题。解决方式就是升级starter版本不要自己硬改源码。第四个是关于C#或其他语言连达梦的题外话。虽然博文主题是SpringBoot但项目中常有其他语言的服务也要连达梦。C#连达梦需要安装达梦官方提供的.NET驱动和Java的驱动类名、URL完全不同。如果你们是多语言团队建议提前在Wiki里把达梦的连接参数按语言整理好别等别的同事踩一遍Java的坑再踩一遍C#的坑。在我做过的几个国产化项目里达梦本身用起来并不复杂真正复杂的是各种默认行为跟MySQL、Oracle的差异交织在一起再加上多数据源这个变量排查难度就会成倍增加。但只要你把连接配置、大小写规则、事务切换这几个关键点理顺了SpringBoot连达梦多数据源这件事就是个熟练活。希望这篇能让你少走点弯路。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。