Spring Boot 2.x基礎(chǔ)教程:Spring Data JPA的多數(shù)據(jù)源配置

上一篇我們介紹了在使用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ō)明與注意

  1. 多數(shù)據(jù)源配置的時(shí)候,與單數(shù)據(jù)源不同點(diǎn)在于spring.datasource之后多設(shè)置一個(gè)數(shù)據(jù)源名稱primarysecondary來(lái)區(qū)分不同的數(shù)據(jù)源配置虐急,這個(gè)前綴將在后續(xù)初始化數(shù)據(jù)源的時(shí)候用到箱残。
  2. 數(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)處理:

  1. 單獨(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配置上抓艳。

  1. 分別創(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目錄:

如果您覺(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厦凤,一起剝皮案震驚了整個(gè)濱河市鼻吮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌较鼓,老刑警劉巖椎木,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異博烂,居然都是意外死亡香椎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)禽篱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)畜伐,“玉大人,你說(shuō)我怎么就攤上這事躺率】窘福” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵肥照,是天一觀的道長(zhǎng)脚仔。 經(jīng)常有香客問(wèn)我,道長(zhǎng)舆绎,這世上最難降的妖魔是什么鲤脏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮吕朵,結(jié)果婚禮上猎醇,老公的妹妹穿的比我還像新娘。我一直安慰自己努溃,他們只是感情好硫嘶,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著梧税,像睡著了一般沦疾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上第队,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天哮塞,我揣著相機(jī)與錄音,去河邊找鬼凳谦。 笑死忆畅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尸执。 我是一名探鬼主播家凯,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼缓醋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了绊诲?” 一聲冷哼從身側(cè)響起送粱,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驯镊,沒(méi)想到半個(gè)月后葫督,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體竭鞍,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡板惑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了偎快。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冯乘。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖晒夹,靈堂內(nèi)的尸體忽然破棺而出裆馒,到底是詐尸還是另有隱情,我是刑警寧澤丐怯,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布喷好,位于F島的核電站,受9級(jí)特大地震影響读跷,放射性物質(zhì)發(fā)生泄漏梗搅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一效览、第九天 我趴在偏房一處隱蔽的房頂上張望无切。 院中可真熱鬧,春花似錦丐枉、人聲如沸哆键。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)籍嘹。三九已至,卻和暖如春弯院,著一層夾襖步出監(jiān)牢的瞬間噩峦,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工抽兆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留识补,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓辫红,卻偏偏與公主長(zhǎng)得像凭涂,于是被迫代替她去往敵國(guó)和親祝辣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359