SpringBoot多數(shù)據(jù)源配置完整指南
一、基礎(chǔ)多數(shù)據(jù)源配置
1. 添加依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- 或者使用其他數(shù)據(jù)庫(kù)驅(qū)動(dòng) -->
2. 配置多個(gè)數(shù)據(jù)源
# 主數(shù)據(jù)源 spring.datasource.primary.url=jdbc:mysql://localhost:3306/db1 spring.datasource.primary.username=root spring.datasource.primary.password=123456 spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver # 次數(shù)據(jù)源 spring.datasource.secondary.url=jdbc:mysql://localhost:3306/db2 spring.datasource.secondary.username=root spring.datasource.secondary.password=123456 spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
3. 配置數(shù)據(jù)源Bean
@Configuration public class DataSourceConfig { // 主數(shù)據(jù)源 @Bean @Primary @ConfigurationProperties(prefix="spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } // 次數(shù)據(jù)源 @Bean @ConfigurationProperties(prefix="spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } }
二、JPA多數(shù)據(jù)源配置
1. 配置主數(shù)據(jù)源JPA
@Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = "com.example.repository.primary", entityManagerFactoryRef = "primaryEntityManagerFactory", transactionManagerRef = "primaryTransactionManager" ) public class PrimaryJpaConfig { @Autowired @Qualifier("primaryDataSource") private DataSource primaryDataSource; @Primary @Bean public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory( EntityManagerFactoryBuilder builder) { return builder .dataSource(primaryDataSource) .packages("com.example.entity.primary") .persistenceUnit("primaryPersistenceUnit") .properties(jpaProperties()) .build(); } private Map<String, Object> jpaProperties() { Map<String, Object> props = new HashMap<>(); props.put("hibernate.hbm2ddl.auto", "update"); props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); return props; } @Primary @Bean public PlatformTransactionManager primaryTransactionManager( @Qualifier("primaryEntityManagerFactory") EntityManagerFactory emf) { return new JpaTransactionManager(emf); } }
2. 配置次數(shù)據(jù)源JPA
@Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = "com.example.repository.secondary", entityManagerFactoryRef = "secondaryEntityManagerFactory", transactionManagerRef = "secondaryTransactionManager" ) public class SecondaryJpaConfig { @Autowired @Qualifier("secondaryDataSource") private DataSource secondaryDataSource; @Bean public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory( EntityManagerFactoryBuilder builder) { return builder .dataSource(secondaryDataSource) .packages("com.example.entity.secondary") .persistenceUnit("secondaryPersistenceUnit") .properties(jpaProperties()) .build(); } private Map<String, Object> jpaProperties() { Map<String, Object> props = new HashMap<>(); props.put("hibernate.hbm2ddl.auto", "update"); props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); return props; } @Bean public PlatformTransactionManager secondaryTransactionManager( @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory emf) { return new JpaTransactionManager(emf); } }
三、MyBatis多數(shù)據(jù)源配置
1. 主數(shù)據(jù)源配置
@Configuration @MapperScan( basePackages = "com.example.mapper.primary", sqlSessionFactoryRef = "primarySqlSessionFactory" ) public class PrimaryMyBatisConfig { @Primary @Bean @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Primary @Bean public SqlSessionFactory primarySqlSessionFactory( @Qualifier("primaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setMapperLocations( new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/primary/*.xml")); return sessionFactory.getObject(); } @Primary @Bean public SqlSessionTemplate primarySqlSessionTemplate( @Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
2. 次數(shù)據(jù)源配置
@Configuration @MapperScan( basePackages = "com.example.mapper.secondary", sqlSessionFactoryRef = "secondarySqlSessionFactory" ) public class SecondaryMyBatisConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory secondarySqlSessionFactory( @Qualifier("secondaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setMapperLocations( new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/secondary/*.xml")); return sessionFactory.getObject(); } @Bean public SqlSessionTemplate secondarySqlSessionTemplate( @Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
四、動(dòng)態(tài)數(shù)據(jù)源配置(運(yùn)行時(shí)切換)
1. 抽象路由數(shù)據(jù)源
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceType(); } }
2. 數(shù)據(jù)源上下文持有者
public class DataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } public static String getDataSourceType() { return contextHolder.get(); } public static void clearDataSourceType() { contextHolder.remove(); } }
3. 配置動(dòng)態(tài)數(shù)據(jù)源
@Configuration public class DynamicDataSourceConfig { @Bean @ConfigurationProperties(prefix="spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix="spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } @Primary @Bean public DataSource dynamicDataSource( @Qualifier("primaryDataSource") DataSource primaryDataSource, @Qualifier("secondaryDataSource") DataSource secondaryDataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("primary", primaryDataSource); targetDataSources.put("secondary", secondaryDataSource); DynamicDataSource dynamicDataSource = new DynamicDataSource(); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(primaryDataSource); return dynamicDataSource; } }
4. 使用AOP切換數(shù)據(jù)源
@Aspect @Component public class DataSourceAspect { @Pointcut("@annotation(com.example.annotation.TargetDataSource)") public void dataSourcePointCut() {} @Before("dataSourcePointCut()") public void before(JoinPoint point) { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); TargetDataSource ds = method.getAnnotation(TargetDataSource.class); if (ds == null) { DataSourceContextHolder.setDataSourceType("primary"); } else { DataSourceContextHolder.setDataSourceType(ds.value()); } } @After("dataSourcePointCut()") public void after(JoinPoint point) { DataSourceContextHolder.clearDataSourceType(); } }
5. 自定義注解
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface TargetDataSource { String value() default "primary"; }
6. 使用示例
@Service public class UserService { @Autowired private UserMapper userMapper; // 使用主數(shù)據(jù)源 public User getPrimaryUser(Long id) { return userMapper.selectById(id); } // 使用次數(shù)據(jù)源 @TargetDataSource("secondary") public User getSecondaryUser(Long id) { return userMapper.selectById(id); } }
五、多數(shù)據(jù)源事務(wù)管理
1. JTA分布式事務(wù)(Atomikos)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> </dependency>
2. 配置JTA數(shù)據(jù)源
# 主數(shù)據(jù)源 spring.jta.atomikos.datasource.primary.unique-resource-name=primaryDS spring.jta.atomikos.datasource.primary.xa-data-source-class-name=com.mysql.cj.jdbc.MysqlXADataSource spring.jta.atomikos.datasource.primary.xa-properties.url=jdbc:mysql://localhost:3306/db1 spring.jta.atomikos.datasource.primary.xa-properties.user=root spring.jta.atomikos.datasource.primary.xa-properties.password=123456 # 次數(shù)據(jù)源 spring.jta.atomikos.datasource.secondary.unique-resource-name=secondaryDS spring.jta.atomikos.datasource.secondary.xa-data-source-class-name=com.mysql.cj.jdbc.MysqlXADataSource spring.jta.atomikos.datasource.secondary.xa-properties.url=jdbc:mysql://localhost:3306/db2 spring.jta.atomikos.datasource.secondary.xa-properties.user=root spring.jta.atomikos.datasource.secondary.xa-properties.password=123456
3. 使用分布式事務(wù)
@Service public class OrderService { @Transactional // 跨數(shù)據(jù)源事務(wù) public void placeOrder(Order order) { // 操作主數(shù)據(jù)源 primaryRepository.save(order); // 操作次數(shù)據(jù)源 auditRepository.logOrder(order); // 如果此處拋出異常,兩個(gè)操作都會(huì)回滾 } }
六、最佳實(shí)踐
命名規(guī)范:
- 為每個(gè)數(shù)據(jù)源使用清晰的命名(如customerDS, orderDS)
- 包結(jié)構(gòu)按數(shù)據(jù)源分離(com.example.repository.primary / .secondary)
連接池配置:
spring.datasource.primary.hikari.maximum-pool-size=10 spring.datasource.secondary.hikari.maximum-pool-size=5
監(jiān)控指標(biāo):
- 為每個(gè)數(shù)據(jù)源配置獨(dú)立的監(jiān)控
- 使用Spring Actuator暴露數(shù)據(jù)源健康指標(biāo)
性能考慮:
- 高頻訪問(wèn)的數(shù)據(jù)源使用更大的連接池
- 讀寫分離場(chǎng)景考慮主從數(shù)據(jù)源
測(cè)試策略:
- 為每個(gè)數(shù)據(jù)源編寫?yīng)毩⒌臏y(cè)試類
- 測(cè)試跨數(shù)據(jù)源事務(wù)的回滾行為
七、常見(jiàn)問(wèn)題解決
問(wèn)題1:循環(huán)依賴
// 解決方法:使用@DependsOn @Bean @DependsOn("dynamicDataSource") public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); }
問(wèn)題2:MyBatis緩存沖突
// 解決方法:為每個(gè)SqlSessionFactory配置獨(dú)立的緩存環(huán)境 sqlSessionFactory.setConfiguration(configuration); configuration.setEnvironment(new Environment( "primaryEnv", transactionFactory, dataSource ));
問(wèn)題3:事務(wù)傳播行為異常
// 解決方法:明確指定事務(wù)管理器 @Transactional(transactionManager = "primaryTransactionManager") public void primaryOperation() {...}
通過(guò)以上配置,Spring Boot應(yīng)用可以靈活地支持多數(shù)據(jù)源場(chǎng)景,無(wú)論是簡(jiǎn)單的多庫(kù)連接還是復(fù)雜的動(dòng)態(tài)數(shù)據(jù)源切換需求。根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景選擇最適合的配置方式,并注意事務(wù)管理和性能調(diào)優(yōu)。
以上就是SpringBoot多數(shù)據(jù)源配置完整指南的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot多數(shù)據(jù)源配置的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java正則表達(dá)式匹配規(guī)則超詳細(xì)總結(jié)
正則表達(dá)式并不僅限于某一種語(yǔ)言,但是在每種語(yǔ)言中有細(xì)微的差別,下面這篇文章主要給大家介紹了關(guān)于java正則表達(dá)式匹配規(guī)則的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10教你怎么用java一鍵自動(dòng)生成數(shù)據(jù)庫(kù)文檔
最近小編也在找這樣的插件,就是不想寫文檔了,浪費(fèi)時(shí)間和心情啊,果然我找到一款比較好用,操作簡(jiǎn)單不復(fù)雜.screw 是一個(gè)簡(jiǎn)潔好用的數(shù)據(jù)庫(kù)表結(jié)構(gòu)文檔的生成工具,支持 MySQL、Oracle、PostgreSQL 等主流的關(guān)系數(shù)據(jù)庫(kù).需要的朋友可以參考下2021-05-05java連接mysql數(shù)據(jù)庫(kù)的方法
這篇文章主要為大家詳細(xì)介紹了java連接mysql數(shù)據(jù)庫(kù)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05通過(guò)Java創(chuàng)建Socket連接到服務(wù)器方式
這篇文章主要介紹了通過(guò)Java創(chuàng)建Socket連接到服務(wù)器方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Spring Boot中使用Activiti的方法教程(二)
工作流(Workflow),就是“業(yè)務(wù)過(guò)程的部分或整體在計(jì)算機(jī)應(yīng)用環(huán)境下的自動(dòng)化”,下面這篇文章主要給大家介紹了關(guān)于Spring Boot中使用Activiti的相關(guān)資料,需要的朋友可以參考下2018-08-08SpringCloud中的@RefreshScope注解與使用場(chǎng)景方式
SpringCloud中的@RefreshScope注解用于動(dòng)態(tài)刷新Bean配置,解決外部配置變化時(shí)的問(wèn)題,避免重啟應(yīng)用,通過(guò)本文的詳細(xì)介紹,希望讀者能夠更好地掌握@RefreshScope的使用技巧,在實(shí)際項(xiàng)目中靈活應(yīng)用,提升微服務(wù)應(yīng)用的動(dòng)態(tài)配置管理能力2024-12-12