Springboot integrates JPA multiple data sources
1. Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.9</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
2. Basic configuration
2.1 DataSource
In the basic configuration, we first configure the basic information of multiple data sources and DataSource, first add the following configuration information in application.yml:
spring:
datasource:
# oracle数据库配置
oracle:
driver-class-name: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@localhost:1521:orcl
username: test
password: test
# mysql数据库配置
mysql:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/swap_business_db?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
# druid数据库连接池
druid:
filters: stat
initialSize: 5
maxActive: 20
maxPoolPreparedStatementPerConnectionSize: 20
maxWait: 60000
minEvictableIdleTimeMillis: 30000
minIdle: 5
poolPreparedStatements: false
testOnBorrow: false
testOnReturn: false
testWhileIdle: true
timeBetweenEvictionRunsMillis: 60000
#Oracle模式
validation-query: SELECT 1 FROM DUAL #用来检测连接是否有效的sql
#MySQL模式
validation-queryM: SELECT 1 #用来检测连接是否有效的sql
jpa:
hibernate:
ddl-auto: none
oracle-dialect: org.hibernate.dialect.Oracle10gDialect
mysql-dialect: org.hibernate.dialect.MySQL8Dialect
show-sql: false
Next, configure two DataSources, as follows:
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.oracle")
@Primary
DataSource dsOracle() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.mysql")
DataSource dsMysql() {
return DruidDataSourceBuilder.create().build();
}
}
Note:@Primary
, this annotation must not be missing, otherwise an error will occur when the project starts. @Primary indicates which instance is used first when there are multiple instances of a certain class.
3. Multiple data source configuration
Next, configure the basic information of Jpa. Here, the two data sources are configured in two classes respectively. The oracle and mysql configurations are as follows:
3.1 JpaConfigOracle
@Configuration
@EnableJpaRepositories(basePackages = "cn.piesat.dao.oracle",
entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanOracle",
transactionManagerRef = "platformTransactionManagerOracle")
public class JpaConfigOracle {
@Autowired
@Qualifier(value = "dsOracle")
DataSource dsOracle;
@Autowired
JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
@Value("${spring.jpa.hibernate.oracle-dialect}")
private String oracleDialect;
@Value("${spring.jpa.show-sql}")
private String showSql;
@Bean
@Primary
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanOracle(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsOracle)
.packages("cn.piesat.model")
.properties(getVendorProperties())
.persistenceUnit("pu1")
.build();
}
/**
* 设置数据源属性
*
* @return
*/
private Map<String, Object> getVendorProperties() {
Map<String, String> map = new HashMap<>();
// 设置oracle数据库方言
map.put("hibernate.dialect", oracleDialect);
map.put("show-sql", showSql);
jpaProperties.setProperties(map);
return hibernateProperties.determineHibernateProperties(
jpaProperties.getProperties(), new HibernateSettings());
}
/**
* 配置事务管理器
*
* @param builder
* @return
*/
@Bean
PlatformTransactionManager platformTransactionManagerOracle(EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean factoryBeanOracle = localContainerEntityManagerFactoryBeanOracle(builder);
return new JpaTransactionManager(factoryBeanOracle.getObject());
}
}
Configuration description: JpaProperties
It is an example provided by the system, and the data inside is the jpa-related configuration we configured in application.yml. HibernateProperties
Used to manually set data source properties, such as defining different database dialects. Then we provide two beans, namely LocalContainerEntityManagerFactoryBean
and PlatformTransactionManager
transaction manager, which are different from MyBatis and JdbcTemplate. In Jpa, transactions must be configured . When providing LocalContainerEntityManagerFactoryBean, you need to specify packages. The package specified here is the location of the entity class corresponding to this data source. In addition, the location of dao is specified by annotation on the configuration class here, and the corresponding references of LocalContainerEntityManagerFactoryBean and PlatformTransactionManager @EnableJpaRepositories
respectively name.
In this way, the first one is configured, and the second one is basically similar to this, with several main differences:
- The location of the dao is different
- persistenceUnit is different
- The name of the related bean is different
3.2 JpaConfigMysql
@Configuration
@EnableJpaRepositories(basePackages = "cn.piesat.dao.mysql",
entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanMysql",
transactionManagerRef = "platformTransactionManagerMysql")
public class JpaConfigMysql {
@Autowired
@Qualifier(value = "dsMysql")
DataSource dsMysql;
@Autowired
JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
@Value("${spring.jpa.hibernate.mysql-dialect}")
private String mysqlDialect;
@Value("${spring.jpa.show-sql}")
private String showSql;
@Bean
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanMysql(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsMysql)
.packages("cn.piesat.model")
.properties(getVendorProperties())
.persistenceUnit("pu2")
.build();
}
/**
* 设置数据源属性
*
* @return
*/
private Map<String, Object> getVendorProperties() {
Map<String, String> map = new HashMap<>();
// 设置mysql数据库方言
map.put("hibernate.dialect", mysqlDialect);
map.put("show-sql", showSql);
jpaProperties.setProperties(map);
return hibernateProperties.determineHibernateProperties(
jpaProperties.getProperties(), new HibernateSettings());
}
/**
* 配置事务管理器
*
* @param builder
* @return
*/
@Bean
PlatformTransactionManager platformTransactionManagerMysql(EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean factoryBeanMysql = localContainerEntityManagerFactoryBeanMysql(builder);
return new JpaTransactionManager(factoryBeanMysql.getObject());
}
}
4. Dao layer interface
Next, provide the relevant entity classes and dao in the corresponding positions. Note: the entity classes can be shared, and the positions of the dao are different.
oracle interface:
package cn.piesat.dao.oracle;
public interface TMasOrbitInfoDao extends JpaRepository<TMasOrbitInfo, String> {
List<TMasOrbitInfo> findBySatelliteAndObservationDateBetween(String satellite, String start, String end);
}
mysql interface:
package cn.piesat.dao.mysql;
public interface SwapBusinessEfficiencyMainDao extends JpaRepository<SwapBusinessEfficiencyMain, String> {
List<SwapBusinessEfficiencyMain> findByDataIdentifyAndDataTimeBetween(String identify, String start, String end);
}
At this point, all configurations are completed, and then different Daos can be injected into the Service, and different Daos operate different data sources.