文档教程后端【免费下载链接】springboot-guideSpringBoot2.0从入门到实战项目地址https://gitcode.com/gh_mirrors/sp/springboot-guide点击查看免费下载本文以 springboot-guide 仓库中的多数据源示例项目为核心完整讲解在 Spring Boot 2.x 环境下通过 Java 配置类为 MyBatis 配置两个独立数据源的全过程。你将学会如何在一个应用内同时连接两个数据库、为不同数据源分别创建 SqlSessionFactory 与事务管理器并借助MapperScan、Qualifier、Primary把不同包下的 Mapper 精确路由到对应的数据源。文中所有代码均可在仓库 source-code/basis/springboot-mybatis/springboot-mybatis-mutipleDatasource 下找到并直接运行验证。一、为什么需要多数据源在上一篇 《Spring Boot 整合 MyBatis》 中我们使用的是单数据源Spring Boot 的自动配置只需要你在application.properties里给出数据库连接参数就可以开箱即用。但实际业务中单数据源往往很快遇到瓶颈业务量大后做数据库拆分按业务域把用户库、订单库、日志库拆到不同 MySQL 实例引入其他数据库读库与写库分离、接入第三方业务库等场景微服务化过程中的过渡方案在服务拆分完成前先让一个应用同时访问多个库。此时 Spring Boot 的自动配置就不够用了——它默认只认spring.datasource.*这一组配置。我们需要手工声明多个数据源 Bean并分别为每个数据源装配一套 MyBatis 的 SqlSessionFactory 和 SqlSessionTemplate这正是本文要解决的核心问题。二、开发前的准备2.1 环境参数项目参数开发工具IDEA基础工具Maven JDK8所用技术Spring Boot MyBatis数据库MySQLSpring Boot 版本2.1.0.RELEASE需要特别提醒Spring Boot 2.0 之后多数据源配置存在一些小坑见下文 2.5 节版本不一致可能导致启动报错请务必留意。仓库中对应模块的pom.xml声明了spring-boot-starter-parent版本为2.1.0.RELEASE、java.version为1.8与本文环境一致可参考 pom.xml。2.2 创建工程与项目结构创建一个基础的 Spring Boot 项目创建步骤与单数据源文章一致这里不再赘述。多数据源的关键在于按数据库拆分包结构springboot-mybatis-mutipleDatasource ├── src/main/java/top/snailclimb │ ├── MainApplication.java # 启动类 │ ├── bean │ │ ├── User.java # 用户实体对应 db1 的 user 表 │ │ └── Money.java # 工资详情实体对应 db2 的 money 表 │ ├── config │ │ ├── DataSource1Config.java # 数据源 1 的配置类 │ │ └── DataSource2Config.java # 数据源 2 的配置类 │ ├── controller │ │ ├── UserController.java # 访问 db1 的接口 │ │ └── MoneyController.java # 访问 db2 的接口 │ ├── db1 │ │ ├── dao/UserDao.java # db1 的 Mapper 接口 │ │ └── service/UserService.java │ └── db2 │ ├── dao/MoneyDao.java # db2 的 Mapper 接口 │ └── service/MoneyService.java └── src/main/resources/application.properties两个数据库的 Dao 与 Service 分属top.snailclimb.db1、top.snailclimb.db2两个包这是后续用MapperScan精确路由的前提。2.3 创建两个数据库和数据表本文共创建两个数据库erp与erp2分别在两个库中建user用户表与money工资详情表。user表只有 4 个字段id、姓名、年龄、余额其中余额 money字段是为了便于演示事务管理money表同样只有 4 个字段id、基本工资、奖金、惩罚金。用户表位于 erp 库CREATE TABLE user ( id int(13) NOT NULL AUTO_INCREMENT COMMENT 主键, name varchar(33) DEFAULT NULL COMMENT 姓名, age int(3) DEFAULT NULL COMMENT 年龄, money double DEFAULT NULL COMMENT 账户余额, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT5 DEFAULT CHARSETutf8工资详情表位于 erp2 库CREATE TABLE money ( id int(33) NOT NULL AUTO_INCREMENT COMMENT 主键, basic int(33) DEFAULT NULL COMMENT 基本工资, reward int(33) DEFAULT NULL COMMENT 奖金, punishment int(33) DEFAULT NULL COMMENT 惩罚金, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT2 DEFAULT CHARSETutf82.4 配置 pom.xml 依赖整合 Spring Boot 与 MyBatis 需要引入mybatis-spring-boot-starter使用 MySQL 则引入mysql-connector-javascope 为 runtime另外加上 web 与 test 依赖dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version1.3.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies2.5 配置 application.propertiesSpring Boot 2.x 的两个坑多数据源配置与单数据源最大的差异在配置键名上。Spring Boot 1.0 时代数据源参数写成spring.datasource.url和spring.datasource.driverClassName升级到 2.0 之后必须改为spring.datasource.jdbc-url和spring.datasource.driver-class-name否则连接数据库时会抛出如下异常### Error querying database. Cause: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.另一个坑是在 2.0.2 版本中datasource 后面需要显式加上hikari前缀Spring Boot 2.x 默认使用 HikariCP 连接池否则同样可能报错。下面是仓库 application.properties 中的真实配置注意文件保存为 GBK 编码若复制后出现乱码请改用 UTF-8 重存server.port8335 # 配置第一个数据源 spring.datasource.hikari.db1.jdbc-urljdbc:mysql://127.0.0.1:3306/erp?useUnicodetruecharacterEncodingutf8useSSLtrueserverTimezoneGMT%2B8 spring.datasource.hikari.db1.usernameroot spring.datasource.hikari.db1.passwordroot spring.datasource.hikari.db1.driver-class-namecom.mysql.cj.jdbc.Driver # 配置第二个数据源 spring.datasource.hikari.db2.jdbc-urljdbc:mysql://127.0.0.1:3306/erp2?useUnicodetruecharacterEncodingutf8useSSLtrueserverTimezoneGMT%2B8 spring.datasource.hikari.db2.usernameroot spring.datasource.hikari.db2.passwordroot spring.datasource.hikari.db2.driver-class-namecom.mysql.cj.jdbc.Driver对配置项逐条说明配置项说明server.port应用端口此处为 8335spring.datasource.hikari.db1.jdbc-url数据源 1 的 JDBC 连接地址指向erp库spring.datasource.hikari.db1.username/.password数据源 1 的账号密码仓库示例为 root请按自身环境修改spring.datasource.hikari.db1.driver-class-nameMySQL 8 的驱动类com.mysql.cj.jdbc.Driverspring.datasource.hikari.db2.*数据源 2 的对应配置指向erp2库关于 JDBC URL 中的参数serverTimezoneGMT%2B8表示东八区时区%2B是的 URL 编码。使用mysql-connector-java6.0本文为 8.x时必须指定时区否则可能报时区错误驱动类也不能再写旧版的com.mysql.jdbc.Driver该写法已废弃控制台会提示The new driver class is com.mysql.cj.jdbc.Driver。另外useSSLtrue与characterEncodingutf8分别控制 SSL 连接与字符集可按实际环境调整。2.6 创建实体 BeanUser.java对应 db1 的user表仓库完整实现见 User.javapublic class User { private int id; private String name; private int age; private double money; // 此处省略 getter、setter 以及 toString 方法 }Money.java对应 db2 的money表见 Money.javapublic class Money { private int basic; private int reward; private int punishment; // 此处省略 getter、setter 以及 toString 方法 }三、数据源配置核心多数据源配置是本文最关键的部分通过两个 Java 配置类分别声明数据源、SqlSessionFactory、事务管理器与 SqlSessionTemplate。整体思路是每个数据源独立拥有一套DataSource → SqlSessionFactory → SqlSessionTemplate并用MapperScan把不同包的 Mapper 绑定到不同的 SqlSessionTemplate 上。3.1 DataSource1Config数据源 1 的配置仓库完整源码见 DataSource1Config.javaConfiguration MapperScan(basePackages top.snailclimb.db1.dao, sqlSessionTemplateRef db1SqlSessionTemplate) public class DataSource1Config { /** * 生成数据源. Primary 注解声明为默认数据源 */ Bean(name db1DataSource) ConfigurationProperties(prefix spring.datasource.hikari.db1) Primary public DataSource testDataSource() { return DataSourceBuilder.create().build(); } /** * 创建 SqlSessionFactory */ Bean(name db1SqlSessionFactory) Primary public SqlSessionFactory testSqlSessionFactory(Qualifier(db1DataSource) DataSource dataSource) throws Exception { SqlSessionFactoryBean bean new SqlSessionFactoryBean(); bean.setDataSource(dataSource); // bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(classpath:mybatis/mapper/db1/*.xml)); return bean.getObject(); } /** * 配置事务管理 */ Bean(name db1TransactionManager) Primary public DataSourceTransactionManager testTransactionManager(Qualifier(db1DataSource) DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } Bean(name db1SqlSessionTemplate) Primary public SqlSessionTemplate testSqlSessionTemplate(Qualifier(db1SqlSessionFactory) SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }3.2 DataSource2Config数据源 2 的配置仓库完整源码见 DataSource2Config.javaConfiguration MapperScan(basePackages top.snailclimb.db2.dao, sqlSessionTemplateRef db2SqlSessionTemplate) public class DataSource2Config { Bean(name db2DataSource) ConfigurationProperties(prefix spring.datasource.hikari.db2) public DataSource testDataSource() { return DataSourceBuilder.create().build(); } Bean(name db2SqlSessionFactory) public SqlSessionFactory testSqlSessionFactory(Qualifier(db2DataSource) DataSource dataSource) throws Exception { SqlSessionFactoryBean bean new SqlSessionFactoryBean(); bean.setDataSource(dataSource); // bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(classpath:mybatis/mapper/db2/*.xml)); return bean.getObject(); } Bean(name db2TransactionManager) public DataSourceTransactionManager testTransactionManager(Qualifier(db2DataSource) DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } Bean(name db2SqlSessionTemplate) public SqlSessionTemplate testSqlSessionTemplate(Qualifier(db2SqlSessionFactory) SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }3.3 三个关键注解与核心概念对照两个配置类逐点解释其作用MapperScan(basePackages ..., sqlSessionTemplateRef ...)指定要扫描的 Mapper 接口包以及这些接口使用的SqlSessionTemplateBean 名称。数据源 1 扫描top.snailclimb.db1.dao并绑定db1SqlSessionTemplate数据源 2 扫描top.snailclimb.db2.dao并绑定db2SqlSessionTemplate从而让不同包的 Mapper 各自路由到对应数据库。SqlSessionTemplate是 MyBatis-Spring 的核心它负责管理 MyBatis 的 SqlSession、调用 MyBatis 的 SQL 方法、翻译异常。它是线程安全的可以被多个 DAO 共享使用。ConfigurationProperties(prefix ...)将application.properties中对应前缀如spring.datasource.hikari.db1的配置绑定到由DataSourceBuilder.create().build()构建的 DataSource 上。注意两个前缀必须与配置文件严格一致。Primary数据源 1 的每个 Bean 都加上了Primary把它声明为默认数据源/默认 Bean否则在自动注入或类型匹配时Spring 会因为存在两个同类型 Bean 而报错NoUniqueBeanDefinitionException。从源码结构看这是保证容器能正常启动的必要条件。Qualifier(db1DataSource)在方法参数上精确指定注入哪个 DataSource Bean避免两个 DataSource 类型的歧义。Bean(name ...)为每个 Bean 起唯一的名字db1DataSource/db2DataSource、db1SqlSessionFactory/db2SqlSessionFactory等供Qualifier与MapperScan引用。bean.setMapperLocations(...)这两行被注释掉了因为本项目采用全注解方式开发SQL 直接写在 Mapper 接口注解里不需要加载 XML如果某个数据源需要 XML Mapper取消注释并按实际路径如classpath:mybatis/mapper/db2/*.xml配置即可。四、Dao 层与 Service 层Dao 与 Service 按数据库拆分为两个包db1user 相关与db2money 相关。4.1 Dao 层Dao 层只做简单的查询演示。关键在于每个 Mapper 接口上都用Qualifier标注它属于哪个 SqlSessionTemplate这与配置类中MapperScan的sqlSessionTemplateRef相呼应。仓库实现见 UserDao.java 与 MoneyDao.java// db1 包下的 UserDao Qualifier(db1SqlSessionTemplate) public interface UserDao { /** * 通过名字查询用户信息 */ Select(SELECT * FROM user WHERE name #{name}) User findUserByName(String name); }// db2 包下的 MoneyDao Qualifier(db2SqlSessionTemplate) public interface MoneyDao { /** * 通过id 查看工资详情 */ Select(SELECT * FROM money WHERE id #{id}) Money findMoneyById(Param(id) int id); }这里使用的是全注解方式Select等SQL 语句较短时比 XML 更清晰简洁如果 SQL 较长或需要复杂动态拼装可以在配置类中放开setMapperLocations并改用 XML 方式两种方式可混用。4.2 Service 层Service 层非常简单不包含复杂业务逻辑只是封装 Dao 调用// db1 包下的 UserService仓库源码见 source-code/basis/springboot-mybatis/springboot-mybatis-mutipleDatasource/src/main/java/top/snailclimb/db1/service/UserService.java Service public class UserService { Autowired private UserDao userDao; /** * 根据名字查找用户 */ public User selectUserByName(String name) { return userDao.findUserByName(name); } }// db2 包下的 MoneyService Service public class MoneyService { Autowired private MoneyDao moneyDao; /** * 根据名字查找用户 */ public Money selectMoneyById(int id) { return moneyDao.findMoneyById(id); } }由于UserDao与MoneyDao处于不同的包、且分别被MapperScan绑定到不同 SqlSessionTemplate这里的Autowired注入不会冲突。五、Controller 层Controller 层同样简单一个接口对应一个数据源// UserController查询 db1 中的用户 RestController RequestMapping(/user) public class UserController { Autowired private UserService userService; RequestMapping(/query) public User testQuery() { return userService.selectUserByName(Daisy); } }// MoneyController查询 db2 中的工资详情 RestController RequestMapping(/money) public class MoneyController { Autowired private MoneyService moneyService; RequestMapping(/query) public Money testQuery() { return moneyService.selectMoneyById(1); } }仓库完整实现见 UserController.java 与 MoneyController.java。注意测试数据要预先插入user表里要有名为Daisy的记录money表里要有 id 为 1 的记录接口才能查到数据。六、启动类启动类与单数据源时几乎一致不需要额外改动源码见 MainApplication.java//此注解表示SpringBoot启动类 SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }两个数据源的MapperScan已写在各自的配置类上因此启动类无需再重复扫描。从源码看该模块还带有标准的上下文加载测试 SpringbootMybatisApplicationTests.java可用mvn test验证容器能否正常装配两个数据源。七、运行验证与常见问题7.1 运行验证保证 MySQL 中存在erp、erp2两个库及对应表并准备测试数据按自身环境修改application.properties中的账号密码启动MainApplication端口 8335浏览器或 curl 访问http://localhost:8335/user/query→ 返回 db1user表中名为 Daisy 的用户 JSONhttp://localhost:8335/money/query→ 返回 db2money表中 id 为 1 的工资详情 JSON。两个接口分别命中两个数据库即说明多数据源配置成功。7.2 常见问题与注意事项jdbcUrl is required with driverClassNameSpring Boot 2.x 中必须使用jdbc-url与driver-class-name键名见 2.5 节。2.0.2 需要hikari前缀spring.datasource.hikari.db1.*中的hikari不能省略。Primary缺失导致启动失败存在两个同类型 DataSource/SqlSessionFactory 时必须用Primary指定默认 Bean否则 Spring 无法确定注入目标。MapperScan的包路径与sqlSessionTemplateRef要配对包扫描错、或sqlSessionTemplateRef名字拼错Mapper 会被绑定到错误的数据源。多数据源事务本文为每个数据源都单独配置了DataSourceTransactionManagerTransactional默认使用Primary标注的 db1 事务管理器跨库事务需要引入分布式事务方案如 JTA这超出本文范围但属于多数据源架构中必须提前考虑的边界。配置文件编码仓库示例的application.properties保存为 GBK 编码建议统一为 UTF-8避免中文注释乱码。八、小结本文基于 springboot-guide 仓库的 多数据源示例模块完整演示了 Spring Boot 2.0 下 MyBatis 双数据源的配置套路配置文件使用带hikari前缀的jdbc-url键名 → 每个数据源一套DataSource/SqlSessionFactory/SqlSessionTemplate/TransactionManagerBean →MapperScan按包绑定 SqlSessionTemplate → Dao 接口用Qualifier标注归属 → 默认数据源加Primary。这套模式可以横向扩展为三数据源、四数据源也是后续读写分离、分库分表等复杂数据架构的基础建议读者结合仓库源码动手实践一遍。赞分享文档教程后端【免费下载链接】springboot-guideSpringBoot2.0从入门到实战项目地址https://gitcode.com/gh_mirrors/sp/springboot-guide点击查看免费下载相关推荐BitCPM-CANN模型家族全面对比8B/3B/1B/0.5B版本如何选择最适合你的方案BitCPM CANN模型家族全面对比8B/3B/1B/0.5B版本如何选择最适合你的方案 BitCPM CANN是首个基于华为昇腾NPU原生构建的端到端1Spring Boot 整合原生 MyBatis 实战基于 mybatis-spring-boot-starter 的 ORM 示例解析Spring Boot 整合原生 MyBatis 实战基于 mybatis spring boot starter 的 ORM 示例解析 本篇技术指南以 sp示例工程后端Talking Head Anime图像要求全解析如何准备完美的256x256 PNG角色素材Talking Head Anime图像要求全解析如何准备完美的256x256 PNG角色素材 Talking Head Anime是一款能够从单张图像生成动上一篇如何快速集成react-native-slider5分钟上手教程下一篇Laravel 二进制UUID教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考