基於Spring Boot與Spring Data JPA的多資料來源配置
由於專案需要,最近研究了一下基於Spring Boot與Spring Data JPA的多資料來源配置問題。以下是傳統的單資料來源配置程式碼。這裡使用的是Spring的Annotation在程式碼內部直接配置的方式,沒有使用任何XML檔案。
@Configuration
@EnableJpaRepositories(basePackages = "org.lyndon.repository")
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class JpaConfig {
private static final String DATABASE_DRIVER = "db.driver";
private static final String DATABASE_URL = "db.url";
private static final String DATABASE_USER = "db.user";
private static final String DATABASE_PASSWORD = "db.password";
private static final String PACKAGES_TO_SCAN = "packages.to.scan";
private static final String HIBERNATE_DIALECT = "hibernate.dialect";
private static final String HIBERNATE_SHOW_SQL = "hibernate.show.sql";
@Resource
private Environment env;
@Bean
public DataSource dataSource() {
DruidDataSource source = new DruidDataSource();
source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER));
source.setUrl(env.getRequiredProperty(DATABASE_URL));
source.setUsername(env.getRequiredProperty(DATABASE_USER));
source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
return source;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN));
factory.setJpaProperties(hibernateProperties());
factory.afterPropertiesSet();
return factory;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager manager = new JpaTransactionManager();
manager.setEntityManagerFactory(entityManagerFactory().getObject());
return manager;
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put(HIBERNATE_DIALECT, env.getRequiredProperty(HIBERNATE_DIALECT));
properties.put(HIBERNATE_SHOW_SQL, env.getRequiredProperty(HIBERNATE_SHOW_SQL));
return properties;
}
}
但是這一配置是不能簡單地擴充套件到多資料來源配置的,因為Spring Boot預設會為開發人員做很多工作,而這些工作與多資料來源的配置相沖突,因此需要修改原來的配置內容。網上有很多講解多資料來源配置的文章,但是這些文章大多使用的是XML配置的方式,而且沒有使用Spring Boot等比較新的Spring框架技術(比如很多人使用實現AbstractRoutingDataSource這一Spring提供的抽象類的方式,還需要切面的支援,無疑是相當繁瑣的),已經不適用於在最新的工程專案中使用了,因為最新的Spring框架可以為我們完成很多事情,我們只需要去適應新的方法即可。為此,我通過研究Spring的官方文件和不斷除錯,實現了新的多資料來源配置的方法,在此貼出,僅供參考。
首先,Spring的JPA是直接支援多資料來源配置的,因此我們可以在配置檔案或者程式碼中直接配置多個資料來源。由於多資料來源配置可能會共享一些配置資訊,因此使用繼承體系實現這種配置是最合適的。在例子中,我的ORM框架使用的是Hibernate,而與Hibernate相關的配置資訊我都放在了配置基類BaseJpaConfg中,程式碼如下。
@Configuration
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class BaseJpaConfig {
private static final String HIBERNATE_DIALECT = "hibernate.dialect";
private static final String HIBERNATE_SHOW_SQL = "hibernate.show.sql";
@Resource
protected Environment env;
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
protected Properties hibernateProperties() {
Properties properties = new Properties();
properties.put(HIBERNATE_DIALECT, env.getRequiredProperty(HIBERNATE_DIALECT));
properties.put(HIBERNATE_SHOW_SQL, env.getRequiredProperty(HIBERNATE_SHOW_SQL));
return properties;
}
}
該類提供Hibernate相關資訊。它有兩個子類,分別是SpringJpaConfig以及MysqlJpaConfig,分別配置了兩個資料來源,連線到兩個不同的資料庫Schema,程式碼如下。
@Configuration
@EnableJpaRepositories(basePackages = {"org.lyndon.repository1"}, entityManagerFactoryRef = "springEntityManagerFactory",
transactionManagerRef = "springTransactionManager")
public class SpringJpaConfig extends BaseJpaConfig {
private static final String DATABASE_DRIVER = "db.driver";
private static final String DATABASE_URL = "db.url";
private static final String DATABASE_USER = "db.user";
private static final String DATABASE_PASSWORD = "db.password";
private static final String PACKAGES_TO_SCAN = "packages.to.scan";
@Bean
@ConfigurationProperties(prefix = "datasource.primary")
public DataSource dataSource() {
DruidDataSource source = new DruidDataSource();
source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER));
source.setUrl(env.getRequiredProperty(DATABASE_URL));
source.setUsername(env.getRequiredProperty(DATABASE_USER));
source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
return source;
}
@Bean(name = "springEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean springEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN).split(","));
factory.setJpaProperties(hibernateProperties());
factory.afterPropertiesSet();
return factory;
}
@Bean(name = "springTransactionManager")
@Primary
public PlatformTransactionManager transactionManager() {
JpaTransactionManager manager = new JpaTransactionManager();
manager.setEntityManagerFactory(springEntityManagerFactory().getObject());
return manager;
}
}
@Configuration
@EnableJpaRepositories(basePackages = {"org.lyndon.repository2"}, entityManagerFactoryRef = "mysqlEntityManagerFactory",
transactionManagerRef = "mysqlTransactionManager")
public class MysqlJpaConfig extends BaseJpaConfig {
private static final String DATABASE_DRIVER = "db.driver";
private static final String DATABASE_URL = "db.url2";
private static final String DATABASE_USER = "db.user";
private static final String DATABASE_PASSWORD = "db.password";
private static final String PACKAGES_TO_SCAN = "packages.to.scan2";
@Bean
@ConfigurationProperties(prefix = "datasource.secondary")
public DataSource dataSource2() {
DruidDataSource source = new DruidDataSource();
source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER));
source.setUrl(env.getRequiredProperty(DATABASE_URL));
source.setUsername(env.getRequiredProperty(DATABASE_USER));
source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
return source;
}
@Bean(name = "mysqlEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource2());
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN).split(","));
factory.setJpaProperties(hibernateProperties());
factory.afterPropertiesSet();
return factory;
}
@Bean(name = "mysqlTransactionManager")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager manager = new JpaTransactionManager();
manager.setEntityManagerFactory(mysqlEntityManagerFactory().getObject());
return manager;
}
}
兩份配置程式碼使用了各自的資料來源、實體管理物件以及事務管理物件。這裡要注意的有兩點,首先是實體管理物件。Spring Boot框架為方便開發者,預設會尋找名為“entityManagerFactory”的Bean作為實體管理的實現,但是我們這裡使用了兩個實體管理物件,名稱也並不是預設的“entityManagerFactory”,因此必須在各自的EnableJpaRepositories的Annotation中指明使用的實體管理物件。第二點,就是事務管理物件。Spring Boot會提供一個預設的事務管理物件的實現,但是我們在這裡使用了兩個不同的事務管理物件,因此我們也需要在各自的EnableJpaRepositories的Annotation中指明使用的事務管理物件。除此以外,我們還必須指定其中一個事務管理物件為主要物件(使用Primary這一Annotation),讓Spring能有主次地使用相應的事務管理物件。
以上就是本文的主要內容。關於Service的配置等問題,由於和單資料來源時是一樣的,因此就不再贅述了。基於上述程式碼,我們就可以使用Spring Boot實現多資料來源之間的無縫切換了,是不是很輕鬆?如果你不想使用程式碼配置的方式,也可以使用XML檔案代替,配置的核心屬性與上文相同,可以自己加以琢磨。
相關文章
- Spring Boot 2.x基礎教程:Spring Data JPA的多資料來源配置Spring Boot
- Spring Boot 多資料來源配置Spring Boot
- Spring Boot 配置多資料來源Spring Boot
- Spring Boot:整合Spring Data JPASpring Boot
- Spring Data JPA系列4——Spring宣告式數事務處理與多資料來源支援Spring
- 使用Spring Boot配置多個資料來源 - UdithSpring Boot
- 基於spring-boot&spring-data-jpa的web開發環境整合SpringbootWeb開發環境
- Spring Boot整合Spring Data JPA進行資料庫操作Spring Boot資料庫
- Spring Boot 2.x基礎教程:MyBatis的多資料來源配置Spring BootMyBatis
- Spring boot 如何快速的配置多個 Redis 資料來源Spring BootRedis
- Spring多資料來源配置Spring
- spring boot 配置 JPASpring Boot
- Spring Boot與多資料來源那點事兒~Spring Boot
- Spring Boot (五)Spring Data JPA 操作 MySQL 8Spring BootMySql
- Spring Boot 原始碼分析 資料來源 + Mybatis 配置Spring Boot原始碼MyBatis
- 使用Spring Boot配置JNDI資料來源 -Roy教程Spring Boot
- Spring Boot + Mybatis 多資料來源配置實現讀寫分離Spring BootMyBatis
- Spring Data JPA如何用於資料庫檢視?Spring資料庫
- Spring Boot 揭祕與實戰(二) 資料儲存篇 – 資料訪問與多資料來源配置Spring Boot
- Spring Data JpaSpring
- Spring Boot中的Mongodb多資料來源擴充套件Spring BootMongoDB套件
- Spring Data JPA之Spring Data JPA快速入門(三)Spring
- spring-boot-route(十)多資料來源切換Springboot
- Spring-Boot 多資料來源配置+動態資料來源切換+多資料來源事物配置實現主從資料庫儲存分離Springboot資料庫
- Spring Data JPA 的使用Spring
- spring boot基於Java的容器配置Spring BootJava
- Spring Boot MyBatis配置多種資料庫Spring BootMyBatis資料庫
- Spring Data Jpa APISpringAPI
- 【教程】Spring+Mybatis環境配置多資料來源SpringMyBatis
- SpringBoot2.x Data JPA 多資料來源爬坑Spring Boot
- Spring Boot 入門系列(二十三)整合Mybatis,實現多資料來源配置!Spring BootMyBatis
- 使用Spring Data JPA進行資料庫操作Spring資料庫
- 談談Spring Boot 資料來源載入及其多資料來源簡單實現Spring Boot
- Spring多資料來源獲取Spring
- Spring Data JPA中TransactionInterceptorSpring
- Spring Data JPA中ConfigurableTransactionManagerSpring
- spring data jpa查詢Spring
- SpringBoot整合Spring Data JPASpring Boot
- Spring Data JPA:解析SimpleJpaRepositorySpring