第 3-6 課:Spring Data JPA 多數據源的使⽤

項⽬中使⽤多個數據源在以往⼯作中⽐較常⻅,微服務架構中不建議⼀個項⽬使⽤多個數據源。在微服務架
構下,⼀個微服務擁有⾃⼰獨⽴的⼀個數據庫,如果此微服務要使⽤其他數據庫的數據,需要調⽤對應庫的
微服務接⼝來調⽤,⽽不是在⼀個項⽬中連接使⽤多個數據庫,這樣微服務更獨⽴、更容易⽔平擴展。
 
雖然在微服務架構下,不提倡⼀個項⽬擁有多個數據源,但在 Spring Boot 體系中,項⽬實現多數據源調⽤
卻是⼀件很容易的事情,本節課將介紹 Spring Data JPA 多數據源的使⽤。
 
Spring Data JPA 使⽤多數據源的整體思路是,配置不同的數據源,在啓動時分別加載多個數據源配置,並且
注⼊到不同的 repository 中。這樣不同的 repository 包就有不同的數據源,使⽤時注⼊對應包下的
repository,就會使⽤對應數據源的操作。
 
對照前兩課的示例項⽬,本課內容將會對項⽬結構有所調整,如下:
其中:
  • confifig 啓動時加載、配置多數據源;GitChat
  • model 存放數據操作的實體類;
  • repository ⽬錄下有兩個包路徑 test1 test2 ,分別代表兩個不同數據源下的倉庫,這兩個包下的 repository 可以相同也可以不同。
下⾯演示⼀下項⽬。
 

多數據源的⽀持

配置 Spring Data JPA 對多數據源的使⽤,⼀般分爲以下⼏步:
  • 創建數據庫 test1 test2
  • 配置多數據源
  • 不同源的 repository 放⼊不同包路徑
  • 聲明不同的包路徑下使⽤不同的數據源、事務⽀持
  • 不同的包路徑下創建對應的 repository
  • 測試使⽤
上⾯的⼀些步驟我們在前⾯兩課中已經講過了,這⾥只補充不同的內容。
配置兩個數據源:
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1?serverTimezon
e=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.primary.username=root
spring.datasource.primary.password=root
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2?serverTimez
one=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.secondary.username=root
spring.datasource.secondary.password=root
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
#SQL 輸出
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
#format ⼀下 SQL 進⾏輸出
spring.jpa.properties.hibernate.format_sql=true
設置將項⽬中的 SQL 格式化後打印出來,⽅便在開發過程中調試跟蹤。
創建 DataSourceConfifig 添加 @Confifiguration 註解,在項⽬啓動時運⾏初始化數據庫資源。
 
@Configuration
public class DataSourceConfig {
}
DataSourceConfifig 類中加載配置⽂件,利⽤ ConfifigurationProperties ⾃動裝配的特性加載兩個數據源。
加載第⼀個數據源,數據源配置以 spring.datasource.primary 開頭,注意當有多個數據源時,需要將其中⼀
個標註爲 @Primary,作爲默認的數據源使⽤。
@Bean(name = "primaryDataSource")
@Primary
@ConfigurationProperties("spring.datasource.primary")
public DataSource firstDataSource() {
 return DataSourceBuilder.create().build();
}
加載第⼆個數據源,數據源配置以 spring.datasource.secondary 爲開頭。
@Bean(name = "secondaryDataSource")
@ConfigurationProperties("spring.datasource.secondary")
public DataSource secondDataSource() {
 return DataSourceBuilder.create().build();
}
加載 JPA 的相關配置信息,JpaProperties JPA 的⼀些屬性配置信息,構建
LocalEntityManagerFactoryBean 需要參數信息注⼊到⽅法中。
@Autowired
private JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
@Bean(name = "vendorProperties")
public Map<String, Object> getVendorProperties() {
 return hibernateProperties.determineHibernateProperties(jpaProperties.getPrope
rties(), new HibernateSettings());
}
第⼀個數據源的加載配置過程
 
⾸先來看第⼀個數據源的加載配置過程,創建 PrimaryConfifig 類,將上⾯創建好的第⼀個數據源注⼊到類
中,添加 @Confifiguration @EnableTransactionManagement 註解,第⼀個代表啓動時加載,第⼆個註解
表示啓⽤事務,同時將第⼀個數據源和 JPA 配置信息注⼊到類中。
 
@Configuration
@EnableTransactionManagement
public class PrimaryConfig {
 @Autowired
 @Qualifier("primaryDataSource")
 private DataSource primaryDataSource;
 @Autowired
 @Qualifier("vendorProperties")
 private Map<String, Object> vendorProperties;
}
LocalEntityManagerFactoryBean 負責創建⼀個適合於僅使⽤ JPA 進⾏數據訪問的環境的 EntityManager
構建的時候需要指明提示實體類的包路徑、數據源和 JPA 配置信息。
@Bean(name = "entityManagerFactoryPrimary")
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityM
anagerFactoryBuilder builder) {
 return builder
 .dataSource(primaryDataSource)
 .properties(vendorProperties)
 .packages("com.neo.model") //設置實體類所在位置
 .persistenceUnit("primaryPersistenceUnit")
 .build();
}
利⽤上⾯的 entityManagerFactoryPrimary() ⽅法構建好最終的 EntityManager
@Bean(name = "entityManagerPrimary")
@Primary
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
 return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
}
EntityManager JPA 中⽤於增、刪、改、查的接⼝,它的作⽤相當於⼀座橋樑,連接內存中的 Java 對象
和數據庫的數據存儲。使⽤ EntityManager 中的相關接⼝對數據庫實體進⾏操作的時候, EntityManager
跟蹤實體對象的狀態,並決定在特定時刻將對實體的操作映射到數據庫操作上⾯。
同時給數據源添加上jpa事務。
@Bean(name = "transactionManagerPrimary")
@Primary
PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder b
uilder) {
 return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObjec
t());
}
最後⼀步最爲關鍵,將我們在類中配置好的 EntityManager 和事務信息注⼊到對應數據源的 repository ⽬錄
下,這樣此⽬錄下的 repository 就會擁有對應數據源和事務的信息。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
 entityManagerFactoryRef="entityManagerFactoryPrimary",
 transactionManagerRef="transactionManagerPrimary",
 basePackages= { "com.neo.repository.test1" })//設置dao(repo)所在位置
public class PrimaryConfig {}
其中,basePackages ⽀持設置多個包路徑,例
如, basePackages= { "com.neo.repository.test1","com.neo.repository.test3" }
到此第⼀個數據源配置完成了。
 
第⼆個數據源的加載配置過程
 
第⼆個數據源配置和第⼀個數據源配置類似,只是⽅法上去掉了註解:@Primary,第⼆個數據源數據源加載
配置類 SecondaryConfifig 完整代碼如下:GitChat
 
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
 entityManagerFactoryRef="entityManagerFactorySecondary",
 transactionManagerRef="transactionManagerSecondary",
 basePackages= { "com.neo.repository.test2" })
public class SecondaryConfig {
 @Autowired
 @Qualifier("secondaryDataSource")
 private DataSource secondaryDataSource;
 @Autowired
 @Qualifier("vendorProperties")
 private Map<String, Object> vendorProperties;
 @Bean(name = "entityManagerFactorySecondary")
 public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (E
ntityManagerFactoryBuilder builder) {
 return builder
 .dataSource(secondaryDataSource)
 .properties(vendorProperties)
 .packages("com.neo.model")
 .persistenceUnit("secondaryPersistenceUnit")
 .build();
 }
 @Bean(name = "entityManagerSecondary")
 public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
 return entityManagerFactorySecondary(builder).getObject().createEntityMana
ger();
 }
 @Bean(name = "transactionManagerSecondary")
 PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBui
lder builder) {
 return new JpaTransactionManager(entityManagerFactorySecondary(builder).ge
tObject());
 }
}
到此多數據源的配置就完成了,項⽬中使⽤哪個數據源的操作,就注⼊對應包下的 repository 進⾏操作即
可,接下來我們對上⾯配置好的數據源進⾏測試。
創建 UserRepositoryTests 測試類,將兩個包下的 repository 都注⼊到測試類中:
 
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserRepositoryTests {
 @Resource
 private UserTest1Repository userTest1Repository;
 @Resource
 private UserTest2Repository userTest2Repository;
}
⾸先測試兩個數據庫中都存⼊數據,數據源1插⼊ 2 條⽤戶信息,數據源2插⼊ 1 條⽤戶信息。
@Test
public void testSave() throws Exception {
 Date date = new Date();
 DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFo
rmat.LONG);
 String formattedDate = dateFormat.format(date);
 userTest1Repository.save(new User("aa", "aa123456","[email protected]", "aa", format
tedDate));
 userTest1Repository.save(new User("bb", "bb123456","[email protected]", "bb", format
tedDate));
 userTest2Repository.save(new User("cc", "cc123456","[email protected]", "cc", format
tedDate));
}
執⾏完測試⽤例後查看數據庫,發現 test1 庫有兩條數據,test2 有⼀條,證明兩個數據源均保存數據正常。
下⾯繼續測試刪除功能,使⽤兩個數據源的 repository 將⽤戶信息全部刪除。
@Test
public void testDelete() throws Exception {
 userTest1Repository.deleteAll();
 userTest2Repository.deleteAll();
}
執⾏完測試⽤例後,發現 test1 庫和 test2 庫⽤戶表的信息已經被清空,證明多數據源刪除成功。
 

總結

Spring Data JPA 通過在啓動時加載不同的數據源,並將不同的數據源注⼊到不同的 repository 包下,從⽽實
現項⽬多數據源操作,在項⽬中使⽤多數據源時,需要⽤到哪個數據源,只需要將對應包下的 repository
⼊操作即可。本課示例中以兩個數據源作爲演示,但其實三個或者更多數據源配置、操作,都可以按照上⾯
⽅法進⾏配置使⽤。
 
 
發佈了89 篇原創文章 · 獲贊 19 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章