springboot+jpa 配置多数据源
springboot+jpa 配置多数据源
使用的springboot的版本是2.2.5
项目结构是
1.在配置文件中添加如下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
<!-- <scope>runtime</scope>-->
</dependency>
2.application.yml文件的配置
server:
port: 8081
spring:
datasource:
first:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/testa?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
username: datahub
password: datahub
second:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/testb?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
username: datahub
password: datahub
jpa:
hibernate:
ddl-auto: update
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
show-sql: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
database: mysql
redis:
database: 0
host: localhost
port: 6379
password:
jedis:
pool:
# 最大连接数,负数表示没有限制
max-active: 8
# 最大阻塞等待时间,负数没有限制
max-wait: -1
# 最大空闲连接
max-idle: 10
# 最小空闲连接
min-idle: 1
# 连接超时时间(ms)
timeout: 1000
备注:这里参数可以随便配置,但是使用spring原生的要对应名称配置。url必须使用jdbc-url的名称
jpa的其他参数,主要是在jpaProperties里面
3.为多数据源配置相应的bean类
3.1 配置DataSourceConfiguration类
package com.example.config;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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;
@Configuration
public class DataSourceConfiguration {
/**
* 第一个数据连接,默认优先级最高
* @return
*/
@Bean(name = "dataSourceFirst")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.first")
public DataSource dataSourceFirst(DataSourceProperties properties){
//这种方式的配置默认只满足spring的配置方式,如果使用其他数据连接(druid),需要自己独立获取配置
return DataSourceBuilder.create().build();
// return DataSourceBuilder.create(properties.getClassLoader())
// .type(HikariDataSource.class)
// .driverClassName(properties.determineDriverClassName())
// .url(properties.determineUrl())
// .username(properties.determineUsername())
// .password(properties.determinePassword())
// .build();
}
/**
* 第二个数据源
* @return
*/
@Bean(name = "dataSourceSecond")
@ConfigurationProperties(prefix = "spring.datasource.second")
public DataSource dataSourceSecond(DataSourceProperties properties){
return DataSourceBuilder.create().build();
// return DataSourceBuilder.create(properties.getClassLoader())
// .type(HikariDataSource.class)
// .driverClassName(properties.determineDriverClassName())
// .url(properties.determineUrl())
// .username(properties.determineUsername())
// .password(properties.determinePassword())
// .build();
}
}
3.2 为每一个数据源配置相应的jpa相关配置
第一个数据源的配置JpaFirstConfiguration类
package com.example.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
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.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"com.example.repository.first"}
)
@EnableTransactionManagement
public class JpaFirstConfiguration {
@Autowired
private HibernateProperties hibernateProperties;
@Autowired
private JpaProperties jpaProperties;
@Autowired
@Qualifier("dataSourceFirst")
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) {
jpaProperties.setShowSql(true);
jpaProperties.setDatabase(Database.MYSQL);
jpaProperties.setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");
jpaProperties.setGenerateDdl(true);
jpaProperties.setOpenInView(true);
Map<String, Object> properties = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
return builder
.dataSource(primaryDataSource)
.packages("com.example.domain.first") //设置实体类所在位置
.persistenceUnit("primaryPersistenceUnit")
.properties(properties)
.build();
}
@Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
}
第二个数据源的配置JpaSecondConfiguration类
package com.example.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
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.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactorySecondary",
transactionManagerRef = "transactionManagerSecondary",
basePackages = {"com.example.repository.second"}
)
@EnableTransactionManagement
public class JpaSecondConfiguration {
@Autowired
private HibernateProperties hibernateProperties;
@Autowired
private JpaProperties jpaProperties;
@Autowired
@Qualifier("dataSourceSecond")
private DataSource secondaryDataSource;
@Primary
@Bean(name = "entityManagerSecondary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactorySecondary(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactorySecondary")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) {
jpaProperties.setShowSql(true);
jpaProperties.setDatabase(Database.MYSQL);
jpaProperties.setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");
jpaProperties.setGenerateDdl(true);
jpaProperties.setOpenInView(true);
Map<String, Object> properties = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
return builder
.dataSource(secondaryDataSource)
.packages("com.example.domain.second") //设置实体类所在位置
.persistenceUnit("secondaryPersistenceUnit")
.properties(properties)
.build();
}
@Bean(name = "transactionManagerSecondary")
public PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
}
}
然后在项目中写两个测试类验证配置是否生效。
4.在配置时遇到的问题及解决方法:
1.一开始的时候在配置工厂类的时候有一行用到的是jpaProperties.getHibernateProperties(new HibernateSettings()),但是在我的项目里面,找不到这个方法。
错误原因:与springboot的版本有关,在springboot2.0.0版本以后,该方法已经被替换掉了,具体的解决方法是可以用下面的一行替代。
hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings())
2.启动报错Access to DialectResolutionInfo cannot be null when ‘hibernate.dialect’ not set
错误原因:因为是自己写的JPA的Confgration,并不是springboot自动配置,所以在application.yml中的JPA配置不会起作用的,需要自己在Confgration类里边自已配置好hibernate.dialect属性
配置方式如下:
jpaProperties.setShowSql(true);
jpaProperties.setDatabase(Database.MYSQL);
jpaProperties.setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");
jpaProperties.setGenerateDdl(true);
jpaProperties.setOpenInView(true);
3.mysql的驱动版本不对,记得换对应数据库版本的驱动包
4、将pom文件中的<packaging>pom</packaging>
给注释掉