04-多数据源配置详解
多数据源配置详解一、知识概述在现代企业应用中,多数据源场景越来越常见:读写分离、分库分表、多租户、异构数据库等。Spring Boot 提供了灵活的多数据源配置方案,但需要开发者手动配置数据源、事务管理器和 ORM 框架的整合。本文将深入讲解 Spring Boot 中多数据源的配置方式,包括静态多数据源、动态数据源切换、读写分离实现、分布式事务处理等内容,帮助你在实际项目中正确处理多数据源场景。二、静态多数据源配置2.1 基础配置/** * 多数据源配置 - 以 MySQL + PostgreSQL 为例 */// application.yml/* spring: datasource: # 主数据源(MySQL) primary: driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/db_primary username: root password: 123456 hikari: minimum-idle: 5 maximum-pool-size: 20 # 从数据源(PostgreSQL) secondary: driver-class-name: org.postgresql.Driver jdbc-url: jdbc:postgresql://localhost:5432/db_secondary username: postgres password: 123456 hikari: minimum-idle: 5 maximum-pool-size: 20 *//** * 主数据源配置 */@Configuration@MapperScan(basePackages="com.example.mapper.primary",sqlSessionFactoryRef="primarySqlSessionFactory")publicclassPrimaryDataSourceConfig{/** * 主数据源 */@Bean(name="primaryDataSource")@ConfigurationProperties(prefix="spring.datasource.primary")@Primary// 标记为默认数据源publicDataSourceprimaryDataSource(){returnDataSourceBuilder.create().build();}/** * 主数据源事务管理器 */@Bean(name="primaryTransactionManager")@PrimarypublicPlatformTransactionManagerprimaryTransactionManager(@Qualifier("primaryDataSource")DataSourcedataSource){returnnewDataSourceTransactionManager(dataSource);}/** * 主数据源 SqlSessionFactory(MyBatis) */@Bean(name="primarySqlSessionFactory")@PrimarypublicSqlSessionFactoryprimarySqlSessionFactory(@Qualifier("primaryDataSource")DataSourcedataSource)throwsException{SqlSessionFactoryBeanfactory=newSqlSessionFactoryBean();factory.setDataSource(dataSource);factory.setMapperLocations(newPathMatchingResourcePatternResolver().getResources("classpath:mapper/primary/*.xml"));// MyBatis 配置org.apache.ibatis.session.Configurationconfiguration=neworg.apache.ibatis.session.Configuration();configuration.setMapUnderscoreToCamelCase(true);factory.setConfiguration(configuration);returnfactory.getObject();}/** * 主数据源 SqlSessionTemplate */@Bean(name="primarySqlSessionTemplate")@PrimarypublicSqlSessionTemplateprimarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory")SqlSessionFactorysqlSessionFactory){returnnewSqlSessionTemplate(sqlSessionFactory);}}/** * 从数据源配置 */@Configuration@MapperScan(basePackages="com.example.mapper.secondary",sqlSessionFactoryRef="secondarySqlSessionFactory")publicclassSecondaryDataSourceConfig{/** * 从数据源 */@Bean(name="secondaryDataSource")@ConfigurationProperties(prefix="spring.datasource.secondary")publicDataSourcesecondaryDataSource(){returnDataSourceBuilder.create().build();}/** * 从数据源事务管理器 */@Bean(name="secondaryTransactionManager")publicPlatformTransactionManagersecondaryTransactionManager(@Qualifier("secondaryDataSource")DataSourcedataSource){returnnewDataSourceTransactionManager(dataSource);}/** * 从数据源 SqlSessionFactory */@Bean(name="secondarySqlSessionFactory")publicSqlSessionFactorysecondarySqlSessionFactory(@Qualifier("secondaryDataSource")DataSourcedataSource)throwsException{SqlSessionFactoryBeanfactory=newSqlSessionFactoryBean();factory.setDataSource(dataSource);factory.setMapperLocations(newPathMatchingResourcePatternResolver().getResources("classpath:mapper/secondary/*.xml"));org.apache.ibatis.session.Configurationconfiguration=neworg.apache.ibatis.session.Configuration();configuration.setMapUnderscoreToCamelCase(true);factory.setConfiguration(configuration);returnfactory.getObject();}/** * 从数据源 SqlSessionTemplate */@Bean(name="secondarySqlSessionTemplate")publicSqlSessionTemplatesecondarySqlSessionTemplate(@Qualifier("secondarySqlSessionFactory")SqlSessionFactorysqlSessionFactory){returnnewSqlSessionTemplate(sqlSessionFactory);}}2.2 多数据源使用/** * 主数据源 Mapper */// 位于 com.example.mapper.primary 包下@MapperpublicinterfacePrimaryUserMapper{UserselectById(Longid);ListUserselectAll();intinsert(Useruser);}// PrimaryUserMapper.xml 位于 classpath:mapper/primary/ 目录/** * 从数据源 Mapper */// 位于 com.example.mapper.secondary 包下@MapperpublicinterfaceSecondaryOrderMapper{OrderselectById(Longid);ListOrderselectByUserId(LonguserId);intinsert(Orderorder);}/** * Service 层使用 */@ServicepublicclassUserOrderService{@AutowiredprivatePrimaryUserMapperprimaryUserMapper;@AutowiredprivateSecondaryOrderMappersecondaryOrderMapper;/** * 查询用户及其订单(跨数据源) */publicUserOrderVOgetUserWithOrders(LonguserId){// 从主数据源查询用户Useruser=primaryUserMapper.selectById(userId);// 从从数据源查询订单ListOrderorders=secondaryOrderMapper.selectByUserId(userId);UserOrderVOvo=newUserOrderVO();vo.setUser(user);vo.setOrders(orders);returnvo;}}/** * 事务管理 - 指定事务管理器 */@ServicepublicclassTransactionalService{@AutowiredprivatePrimaryUserMapperprimaryUserMapper;@AutowiredprivateSecondaryOrderMappersecondaryOrderMapper;/** * 主数据源事务 */@Transactional(transactionManager="primaryTransactionManager")publicvoidsaveUser(Useruser){primaryUserMapper.insert(user);}/** * 从数据源事务 */@Transactional(transactionManager="secondaryTransactionManager")publicvoidsaveOrder(Orderorder){secondaryOrderMapper.insert(order);}/** * 跨数据源事务(需要分布式事务) * 以下方式无法保证事务一致性! */@Transactional(transactionManager="primaryTransactionManager")publicvoidsaveUserAndOrder(Useruser,Orderorder){primaryUserMapper.insert(user);// 这里切换到从数据源,但事务管理器仍是 primaryTransactionManager// 无法保证跨数据源的事务一致性!secondaryOrderMapper.insert(order);}}2.3 JPA 多数据源配置/** * JPA 多数据源配置 */@Configuration@EnableJpaRepositories(basePackages="com.example.repository.primary",entityManagerFactoryRef="primaryEntityManagerFactory",transactionManagerRef="primaryTransactionManager")publicclassPrimaryJpaConfig{@Bean(name="primaryDataSource")@ConfigurationProperties(prefix="spring.datasource.primary")@PrimarypublicDataSourceprimaryDataSource(){returnDataSourceBuilder.create().build();}@Bean(name="primaryEntityManagerFactory")@PrimarypublicLocalContainerEntityManagerFactoryBeanprimaryEntityManagerFactory(EntityManagerFactoryBuilderbuilder,@Qualifier("primaryDataSource")DataSourcedataSource){returnbuilder.dataSource(dataSource).packages("com.example.entity.primary").persistenceUnit("primary").properties(Map.of("hibernate.hbm2ddl.auto","update","hibernate.show_sql","true")).build();}@Bean(name="primaryTransactionManager")@PrimarypublicPlatformTransactionManagerprimaryTransactionManager(@Qualifier("primaryEntityManagerFactory")EntityManagerFactoryentityManagerFactory){returnnewJpaTransactionManager(entityManagerFactory);}}@Configuration@EnableJpaRepositories(basePackages="com.example.repository.secondary",entityManagerFactoryRef="secondaryEntityManagerFactory",transactionManagerRef="secondaryTransactionManager")publicclassSecondaryJpaConfig{@Bean(name="secondaryDataSource")@ConfigurationProperties(prefix="spring.datasource.secondary")publicDataSourcesecondaryDataSource(){returnDataSourceBuilder.create().build();}@Bean(name="secondaryEntityManagerFactory")publicLocalContainerEntityManagerFactoryBeansecondaryEntityManager