springboot + JPA Configuration Dual Data Source Actual Combat
- 2021-11-10 09:50:00
- OfStack
springboot + JPA Configuration Dual Data Sources
1. First configure the application. yml file to set the master-slave database
spring:
servlet:
multipart:
max-file-size: 20MB
max-request-size: 20MB
profiles:
active: @activatedProperties@
thymeleaf:
mode: LEGACYHTML5
encoding: UTF-8
cache: false
http:
encoding:
charset: UTF-8
enabled: true
force: true
jpa:
hibernate:
ddl-auto: none
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
show-sql: true
database: mysql
datasource:
primary:
jdbc-url: jdbc:mysql://192.168.2.180:3306/ssdt-rfid?serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
secondary:
jdbc-url: jdbc:mysql://127.0.0.1:3306/isite?serverTimezone=Asia/Shanghai
username: root
password: 654321
driver-class-name: com.mysql.cj.jdbc.Driver
There are two configurations in datasource: primary (primary data source) and secondary (secondary data source).
dialect: org. hibernate. dialect. MySQL5Dialect configuration
MySQLDialect is prior to MySQL5. X and MySQL5Dialect is subsequent to MySQL5. X
2. Use the configuration class to read the two data sources configured by application. yml
And inject it into the IOC container of Spring
package com.springboot.***.***.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
/**
* @author : SUN
* @version: 1.0
* @date : 2019/12/24 13:12
* @description :
*/
@Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary") // Read configuration file master data source parameters
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryDataSource")
@Qualifier("secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary") // Reading configuration file secondary data source parameters
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
Annotation explanation:
@Configuration
SpringBoot Startup uses this class as a configuration class and loads it with configuration file 1
@Bean
Inject the entity into the IOC container
@Qualifier
Specifies the data source name, the same principle as the name attribute in Bean, primarily to ensure successful injection
@Primary
Specify the master data source
@ConfigurationProperties
Read the data source in the configuration file into the method for build
3. Then configure two data sources through classes
The DAO layer interface of primary and secondary data sources and the entity POJO class should be placed in different directories, and the paths are specified in the following two configuration classes respectively
(1) Master data source
package com.springboot.****.****.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @author : SUN
* @version: 1.0
* @date : 2019/12/24 13:25
* @description :
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"com.springboot.****.****.repository"}) // Object for the data source operation DAO Interface packages are distinguished from secondary data sources
public class PrimaryConfig {
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@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.springboot.****.****.domain.entity") // Set the entity class location to distinguish from the secondary data source
.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) Secondary data source
package com.springboot.****.****.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @author : SUN
* @version: 1.0
* @date : 2019/12/24 13:59
* @description :
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactorySecondary",
transactionManagerRef = "transactionManagerSecondary",
basePackages = {"com.springboot.****.****.secRepository"}) // Settings DAO The packet location of the interface layer is distinguished from the main data source
public class SecondaryConfig {
@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource;
@Bean(name = "entityManagerSecondary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactorySecondary(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactorySeAcondary")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(secondaryDataSource)
.properties(getVendorProperties())
.packages("com.springboot.****.****.secEntity") // Set the location of the package where the entity class is located to distinguish from the main data source
.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());
}
}
These two classes mainly configure each data source, including transaction manager, entity manager and so on.
Note: You must specify the package where the DAO interface resides and the package where the entity class resides. Each data source mainly operates on the resource it specifies (DAO interface CURD, entity class)
4. Start the main function entry of the class
The SpringBoot startup class needs to close the annotation--program startup loaded repository (@ EnableJpaRepositories) because it is already open in the data source configuration class
@SpringBootApplication
@EnableAsync // Open asynchronous call
//@EnableJpaRepositories(basePackages = {""}
public class TouchPmsApplication {
public static void main(String[] args) {
SpringApplication.run(TouchPmsApplication.class, args);
}
}