上一篇我們介紹了在使用JdbcTemplate來(lái)做數(shù)據(jù)訪問(wèn)時(shí)候的多數(shù)據(jù)源配置實(shí)現(xiàn)。接下來(lái)我們繼續(xù)學(xué)習(xí)如何在使用Spring Data JPA的時(shí)候凿傅,完成多數(shù)據(jù)源的配置和使用。
添加多數(shù)據(jù)源的配置
先在Spring Boot的配置文件application.properties
中設(shè)置兩個(gè)你要鏈接的數(shù)據(jù)庫(kù)配置数苫,比如這樣:
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
# 日志打印執(zhí)行的SQL
spring.jpa.show-sql=true
# Hibernate的DDL策略
spring.jpa.hibernate.ddl-auto=create-drop
這里除了JPA自身相關(guān)的配置之外聪舒,與JdbcTemplate配置時(shí)候的數(shù)據(jù)源配置完全是一致的
說(shuō)明與注意:
- 多數(shù)據(jù)源配置的時(shí)候,與單數(shù)據(jù)源不同點(diǎn)在于
spring.datasource
之后多設(shè)置一個(gè)數(shù)據(jù)源名稱primary
和secondary
來(lái)區(qū)分不同的數(shù)據(jù)源配置虐急,這個(gè)前綴將在后續(xù)初始化數(shù)據(jù)源的時(shí)候用到箱残。 - 數(shù)據(jù)源連接配置2.x和1.x的配置項(xiàng)是有區(qū)別的:2.x使用
spring.datasource.secondary.jdbc-url
,而1.x版本使用spring.datasource.secondary.url
止吁。如果你在配置的時(shí)候發(fā)生了這個(gè)報(bào)錯(cuò)java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
被辑,那么就是這個(gè)配置項(xiàng)的問(wèn)題。
初始化數(shù)據(jù)源與JPA配置
完成多數(shù)據(jù)源的配置信息之后敬惦,就來(lái)創(chuàng)建個(gè)配置類來(lái)加載這些配置信息盼理,初始化數(shù)據(jù)源,以及初始化每個(gè)數(shù)據(jù)源要用的JdbcTemplate俄删。
由于JPA的配置要比JdbcTemplate的負(fù)責(zé)很多宏怔,所以我們將配置拆分一下來(lái)處理:
- 單獨(dú)建一個(gè)多數(shù)據(jù)源的配置類,比如下面這樣:
@Configuration
public class DataSourceConfiguration {
@Primary
@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();
}
}
可以看到內(nèi)容跟JdbcTemplate時(shí)候是一模一樣的畴椰。通過(guò)@ConfigurationProperties
可以知道這兩個(gè)數(shù)據(jù)源分別加載了spring.datasource.primary.*
和spring.datasource.secondary.*
的配置臊诊。@Primary
注解指定了主數(shù)據(jù)源,就是當(dāng)我們不特別指定哪個(gè)數(shù)據(jù)源的時(shí)候斜脂,就會(huì)使用這個(gè)Bean真正差異部分在下面的JPA配置上抓艳。
- 分別創(chuàng)建兩個(gè)數(shù)據(jù)源的JPA配置。
Primary數(shù)據(jù)源的JPA配置:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef="entityManagerFactoryPrimary",
transactionManagerRef="transactionManagerPrimary",
basePackages= { "com.didispace.chapter38.p" }) //設(shè)置Repository所在位置
public class PrimaryConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@Autowired
private JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
private Map<String, Object> getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
@Primary
@Bean(name = "entityManagerPrimary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
}
@Primary
@Bean(name = "entityManagerFactoryPrimary")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
return builder
.dataSource(primaryDataSource)
.packages("com.didispace.chapter38.p") //設(shè)置實(shí)體類所在位置
.persistenceUnit("primaryPersistenceUnit")
.properties(getVendorProperties())
.build();
}
@Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
}
Secondary數(shù)據(jù)源的JPA配置:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef="entityManagerFactorySecondary",
transactionManagerRef="transactionManagerSecondary",
basePackages= { "com.didispace.chapter38.s" }) //設(shè)置Repository所在位置
public class SecondaryConfig {
@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource;
@Autowired
private JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
private Map<String, Object> getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
@Bean(name = "entityManagerSecondary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactorySecondary(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactorySecondary")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) {
return builder
.dataSource(secondaryDataSource)
.packages("com.didispace.chapter38.s") //設(shè)置實(shí)體類所在位置
.persistenceUnit("secondaryPersistenceUnit")
.properties(getVendorProperties())
.build();
}
@Bean(name = "transactionManagerSecondary")
PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
}
}
說(shuō)明與注意:
- 在使用JPA的時(shí)候帚戳,需要為不同的數(shù)據(jù)源創(chuàng)建不同的package來(lái)存放對(duì)應(yīng)的Entity和Repository玷或,以便于配置類的分區(qū)掃描
- 類名上的注解
@EnableJpaRepositories
中指定Repository的所在位置 -
LocalContainerEntityManagerFactoryBean
創(chuàng)建的時(shí)候,指定Entity所在的位置 - 其他主要注意在互相注入時(shí)候片任,不同數(shù)據(jù)源不同配置的命名庐椒,基本就沒(méi)有什么大問(wèn)題了
測(cè)試一下
完成了上面之后,我們就可以寫(xiě)個(gè)測(cè)試類來(lái)嘗試一下上面的多數(shù)據(jù)源配置是否正確了蚂踊,比如下面這樣:
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter38ApplicationTests {
@Autowired
private UserRepository userRepository;
@Autowired
private MessageRepository messageRepository;
@Test
public void test() throws Exception {
userRepository.save(new User("aaa", 10));
userRepository.save(new User("bbb", 20));
userRepository.save(new User("ccc", 30));
userRepository.save(new User("ddd", 40));
userRepository.save(new User("eee", 50));
Assert.assertEquals(5, userRepository.findAll().size());
messageRepository.save(new Message("o1", "aaaaaaaaaa"));
messageRepository.save(new Message("o2", "bbbbbbbbbb"));
messageRepository.save(new Message("o3", "cccccccccc"));
Assert.assertEquals(3, messageRepository.findAll().size());
}
}
說(shuō)明與注意:
- 測(cè)試驗(yàn)證的邏輯很簡(jiǎn)單约谈,就是通過(guò)不同的Repository往不同的數(shù)據(jù)源插入數(shù)據(jù),然后查詢一下總數(shù)是否是對(duì)的
- 這里省略了Entity和Repository的細(xì)節(jié)犁钟,讀者可以在下方代碼示例中下載完整例子對(duì)照查看
代碼示例
本文的相關(guān)例子可以查看下面?zhèn)}庫(kù)中的chapter3-8
目錄:
- Github:https://github.com/dyc87112/SpringBoot-Learning/
- Gitee:https://gitee.com/didispace/SpringBoot-Learning/
如果您覺(jué)得本文不錯(cuò)棱诱,歡迎Star支持,您的關(guān)注是我堅(jiān)持的動(dòng)力涝动!
相關(guān)閱讀
本文首發(fā):Spring Boot 2.x基礎(chǔ)教程:Spring Data JPA的多數(shù)據(jù)源配置迈勋,轉(zhuǎn)載請(qǐng)注明出處。
歡迎關(guān)注我的公眾號(hào):程序猿DD醋粟,獲得獨(dú)家整理的學(xué)習(xí)資源和日常干貨推送靡菇。
如果您對(duì)我的其他專題內(nèi)容感興趣重归,直達(dá)我的個(gè)人博客:didispace.com。