紀錄一下我自己在處理這問題的筆記
整理 package
假設我有兩個資料庫連線:
- (MySQL) 192.168.1.100:3306/db
- (MS SQL Server) 192.168.2.200:1433;databaseName=hr;
- (MySQL) 192.168.1.110:3306/sys_setting
- ……等等
那首先,先把 repository、Hibernate Entity classes都整理好,不同連線的要放在不同 package
例如
資料庫 | package |
---|---|
jdbc:mysql://192.168.1.100:3306/db | org.example.database.db.models |
org.example.database.db.repositories | |
jdbc:sqlserver://192.168.2.200:1433;databaseName=hr | org.example.database.hr.models |
org.example.database.hr.repositories |
如果資料庫連線全都是使用 repository,Service(DAO)沒有直接使用到 DataSource、EntityManager、TransactionManager的話,可以不用特別移動。
像是下面這個 Service,去連資料庫是 HRUserRepository 做的,而不是 HRUserService,那 HRUserService 就沒有必要移動
import org.example.database.hr.repositories.HRUserRepository;
// ... 其他 import
@Service
public class HRUserService(){
private HRUserRepository repository;
public HRUser getUserName(String id){
return repository.findNameById(id);
}
}
設置 Bean
再來就是設定好連線的 config:
import java.util.HashMap;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableJpaRepositories(
/*
* basePackages 填上會使用這邊的連線的 package。
* 如果只有少數幾個 class 會使用到,也可以使用 basePackageClasses ,
* 例如
* @EnableJpaRepositories(
* basePackageClasses = XXXRepository.class
* )
*/
basePackages = {
"org.example.database.db.models",
"org.example.database.db.repositories"
},
entityManagerFactoryRef = "MySQLDBEntityManagerFactory",
transactionManagerRef = "MySQLDBTransactionManager"
)
@EnableTransactionManagement
public class MySQLDBConnectionConfig {
/*
* 建立 DataSource。
* 這邊我使用 Spring 從 properties 注入。
* 我在網路上查到可以用以下方式來寫
*
* @Bean("MySQLDBDataSource")
* @ConfigurationProperties("spring.datasource.mysqldb")
* public DataSource DataSource(){
* return DataSourceBuilder.create().build();
* }
* 但我沒法成功,所以改用注入參數處理
*/
@Bean("MySQLDBDataSource")
public DataSource DataSource(
@Value("${spring.datasource.mysqldb.url}") String jdbcURL,
@Value("${spring.datasource.mysqldb.username}") String user,
@Value("${spring.datasource.mysqldb.password}") String password,
@Value("${spring.datasource.mysqldb.driverClass}") String driverClassName
) {
return DataSourceBuilder.create()
.driverClassName(driverClassName)
.url(jdbcURL)
.username(user)
.password(password)
.build();
}
@Bean("MySQLDBEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean EntityManagerFactory(
@Qualifier("MySQLDBDataSource") DataSource ds) {
EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), new HashMap<>(), null);
return builder.dataSource(ds)
.packages("org.example.database.db")
.persistenceUnit("mysqldb")
.build();
}
@Bean("MySQLDBTransactionManager")
public PlatformTransactionManager TransactionManager(
@Qualifier("MySQLDBEntityManagerFactory") LocalContainerEntityManagerFactoryBean emf) {
return new JpaTransactionManager(emf.getObject());
}
}
每個連線都依次處理
@Configuration
@EnableJpaRepositories(
// 中略
)
@EnableTransactionManagement
public class HRDBConnectionConfig{
@Bean("HRDataSource")
public DataSource DataSource(/* 注入的參數…… */) {
// 中略
}
@Bean("HREntityManagerFactory")
public LocalContainerEntityManagerFactoryBean EntityManagerFactory(
@Qualifier("HRDataSource") DataSource cDataSource,
EntityManagerFactoryBuilder builder) {
// 中略
}
@Bean("HRTransactionManager")
public PlatformTransactionManager cTransactionManager(
@Qualifier("HREntityManagerFactory") LocalContainerEntityManagerFactoryBean emf
) {
return new JpaTransactionManager(emf.getObject());
}
}
參考資料
黃紹溥. (2021, December 5). Spring Boot + Spring Data JPA 配置多個 DataSource. 昕力大學. https://www.tpisoftware.com/tpu/articleDetails/2637
P-c lin. (2021, September 12). 具有多個 DataSource 的 Spring Data JPA. HackMD. https://hackmd.io/@pclin/rJB8Mfu-t
Bingdoal. (2022, September 12). Spring Boot JPA 下套用多個資料庫來源. Bingdoal. https://bingdoal.github.io/backend/2022/09/spring-boot-jpa-multiple-datasource/
沒有留言:
張貼留言