本文章使用的是持久化框架為JPA,所以數據源也是基於JPA。采用的是SpringBoot2 + SpringDataJPA + MySQL + 雙數據源!
一、雙數據源的適用場景:
1、主從庫分離(數據庫讀寫分離)
2、數據遷移
3、系統版本升級,數據庫升級到另外一款
二、application.yml中配置
spring:
jpa:
hibernate:
ddl-auto: create
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
open-in-view: true
show-sql: true
generate-ddl: true
datasource: #database
primary: # 3.0 Datasource
jdbc-url: jdbc:mysql://127.0.0.1:3306/gtu?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
secondary: # 2.0 Datasource
jdbc-url: jdbc:mysql://127.0.0.1:3306/gtu-not-completed?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
注:配置文件中需要指定兩個數據源,這里在配置的時候是沒有自動提示的,因為這是我們自定義的,需要在程序中動態讀取。
三、讀取application.yml配置的兩個數據源,並將其注入到Spring的IOC容器中
@Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryDataSource")
@Qualifier("secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
注解解釋:
@Configuration:SpringBoot啟動將該類作為配置類,同配置文件一起加載
@Bean:將該實體注入到IOC容器中
@Qualifier:指定數據源名稱,與Bean中的name屬性原理相同,主要是為了確保注入成功
@Primary:指定主數據源
@ConfigurationProperties:將配置文件中的數據源讀取進到方法中,進行build
四、以類的方式配置兩個數據源
(1)主數據源(對應DataSourceConfig類中的primaryDataSource)
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"com.gtcloud.repository"}) // 指定該數據源操作的DAO接口包
public class PrimaryConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@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)
.properties(getVendorProperties())
.packages("com.gtcloud.model") //設置實體類所在位置
.persistenceUnit("primaryPersistenceUnit")
.build();
}
private Map getVendorProperties() {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
properties.put("hibernate.ddl-auto",
"create");
properties.put("hibernate.physical_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
properties.put("hibernate.implicit_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
return properties;
}
@Autowired
private Environment env;
@Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
}
(2)從(次)數據源
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactorySecondary",
transactionManagerRef = "transactionManagerSecondary",
basePackages = {"com.gtmove.repository"}) //設置DAO接口層所在包位置
public class SecondaryConfig {
@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource;
@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)
.properties(getVendorProperties())
.packages("com.gtmove.model") //設置實體類所在包的位置
.persistenceUnit("primaryPersistenceUnit")
.build();
}
private Map getVendorProperties() {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.ddl-auto",
env.getProperty("update"));
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
properties.put("hibernate.physical_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
properties.put("hibernate.implicit_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
return properties;
}
@Autowired
private Environment env;
@Bean(name = "transactionManagerSecondary")
PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
}
}
這兩個類主要配置每個數據源,包括事務管理器、以及實體管理器等配置。
注:必須要指定DAO接口所在的包以及實體類所在的包。每個數據源主要操作它指定的資源(DAO接口CURD、實體類)
五、注意點:
1、SpringBoot啟動類必須關閉 --程序啟動加載的倉庫(@EnableJpaRepositories),因為在數據源配置類中已經開啟了。如果沒有去掉,程序會跑不起來!
@SpringBootApplication(scanBasePackages = {""}) // 指定加載程序主包,存在默認值【可選】
//@EntityScan({""})
//@EnableJpaRepositories(basePackages = {""})
public class Gt3datamoverApplication {
public static void main(String[] args) {
SpringApplication.run(Gt3datamoverApplication.class, args);
}
}
2、如果需要對數據源連接的表進行DDL(正向生成表、程序啟動動態更新表),需要在PrimaryConfig類中 / SecondaryConfig類中的getVendorProperties()方法中進行手動設置(此教程都已設置好了!)