工作中难免会需要用到多个数据库,这里介绍一下jpa配置多数据源
先看配置文件信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.jpa.show-sql=true spring.datasource.database1.url:jdbc:mysql://ip:端口/库名?verifyServerCertificate=false&useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.database1.username=root spring.datasource.database1.password=123456 spring.datasource.database1.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.database2.url:jdbc:sqlserver://ip:1433;Databasename=数据库名 spring.datasource.database2.username=SA spring.datasource.database2.password=123456 spring.datasource.database2.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver spring.jpa.hibernate.main-dialect=org.hibernate.dialect.SQLServer2008Dialect #SQLServer 连接超时配置 #验证连接的有效性 spring.datasource.secondary.test-while-idle=true #获取连接时候验证,会影响性能 spring.datasource.secondary.test-on-borrow=true spring.datasource.secondary.validation-query=SELECT 1 #空闲连接回收的时间间隔,与test-while-idle一起使用,设置5分钟 spring.datasource.secondary.time-between-eviction-runs-millis=300000 #连接池空闲连接的有效时间 ,设置30分钟 spring.datasource.secondary.min-evictable-idle-time-millis=1800000
然后我们需要写两个Properties来读取配置文件里面的配置信息
/** * 数据源1 */ @ConfigurationProperties(prefix = "spring.datasource.database1") @Component @Data public class DataBase1Properties { private String url; private String username; private String password; private String driverClassName; }
/** * 数据源2 */ @ConfigurationProperties(prefix = "spring.datasource.database2") @Component @Data public class DataBase2Properties { private String url; private String username; private String password; private String driverClassName; }
配置文件读出来了,就直接去创建DataSource吧
@Configuration @Slf4j public class DataSourceConfiger { @Autowired private DataBase1Properties dataBase1Properties; @Autowired private DataBase2Properties dataBase2Properties; @Autowired private DataBase3Properties dataBase3Properties; @Bean(name = "dataSource1") @Primary public DataSource dataSource1(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(dataBase1Properties.getUrl()); dataSource.setUsername(dataBase1Properties.getUsername()); dataSource.setPassword(dataBase1Properties.getPassword()); dataSource.setDriverClassName(dataBase1Properties.getDriverClassName()); return dataSource; } @Bean(name = "dataSource2") public DataSource dataSource2(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(dataBase2Properties.getUrl()); dataSource.setUsername(dataBase2Properties.getUsername()); dataSource.setPassword(dataBase2Properties.getPassword()); dataSource.setDriverClassName(dataBase2Properties.getDriverClassName()); return dataSource; }
}
好了,两个数据源创建好了,后面需要针对数据源进行一些配置
@Configuration //开启事务支持 @EnableTransactionManagement @EnableJpaRepositories( //配置实体管理工厂引用名称 entityManagerFactoryRef ="entityManagerFactoryDataBase1", //配置事务管理工厂引用名称 transactionManagerRef = "transactionManagerDatabase1", //配置扫描Repositories所在的package及子package basePackages = "com.src.dao.datasource1" ) public class DataBase1Configer { @Autowired @Qualifier(value = "dataSource1") private DataSource dataSource1; private final ObjectProvider<SchemaManagementProvider> providers; private final HibernateProperties hibernateProperties; private final JpaProperties properties; private final ObjectProvider<PhysicalNamingStrategy> physicalNamingStrategy; private final ObjectProvider<ImplicitNamingStrategy> implicitNamingStrategy; private final ConfigurableListableBeanFactory beanFactory; private final ObjectProvider<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers; @Autowired public DataBase1Configer(ObjectProvider<SchemaManagementProvider> providers, HibernateProperties hibernateProperties, JpaProperties properties, ObjectProvider<PhysicalNamingStrategy> physicalNamingStrategy, ObjectProvider<ImplicitNamingStrategy> implicitNamingStrategy, ConfigurableListableBeanFactory beanFactory, ObjectProvider<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers) { this.providers = providers; this.hibernateProperties = hibernateProperties; this.properties = properties; this.physicalNamingStrategy = physicalNamingStrategy; this.implicitNamingStrategy = implicitNamingStrategy; this.beanFactory = beanFactory; this.hibernatePropertiesCustomizers = hibernatePropertiesCustomizers; } @Bean(name = "entityManagerFactoryDataBase1") @Primary public LocalContainerEntityManagerFactoryBean entityManagerFactoryDataBase1(EntityManagerFactoryBuilder builder){ return builder .dataSource(dataSource1) .packages("com.src.model.datasource1") .properties(getVendorProperties(dataSource1)) .persistenceUnit("database1PersistenceUnit") .build(); } /** * 配置事物管理器 * * @param builder * @return */ @Bean(name = "transactionManagerDatabase1") PlatformTransactionManager transactionManagerDatabase1(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactoryDataBase1(builder).getObject()); } /** * 获取配置文件信息 * * @param dataSource * @return */ private Map<String, Object> getVendorProperties(DataSource dataSource) { List<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers( physicalNamingStrategy.getIfAvailable(), implicitNamingStrategy.getIfAvailable(), beanFactory, this.hibernatePropertiesCustomizers.orderedStream() .collect(Collectors.toList())); Supplier<String> defaultDdlMode = () -> new HibernateDefaultDdlAutoProvider(providers) .getDefaultDdlAuto(dataSource); return new LinkedHashMap<>(this.hibernateProperties.determineHibernateProperties( properties.getProperties(), new HibernateSettings().ddlAuto(defaultDdlMode) .hibernatePropertiesCustomizers( hibernatePropertiesCustomizers))); } /** * 命名策略自动判断 * * @param physicalNamingStrategy * @param implicitNamingStrategy * @param beanFactory * @param hibernatePropertiesCustomizers * @return */ private List<HibernatePropertiesCustomizer> determineHibernatePropertiesCustomizers( PhysicalNamingStrategy physicalNamingStrategy, ImplicitNamingStrategy implicitNamingStrategy, ConfigurableListableBeanFactory beanFactory, List<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers) { List<HibernatePropertiesCustomizer> customizers = new ArrayList<>(); if (ClassUtils.isPresent( "org.hibernate.resource.beans.container.spi.BeanContainer", getClass().getClassLoader())) { customizers .add((properties) -> properties.put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory))); } if (physicalNamingStrategy != null || implicitNamingStrategy != null) { customizers.add(new NamingStrategiesHibernatePropertiesCustomizer( physicalNamingStrategy, implicitNamingStrategy)); } customizers.addAll(hibernatePropertiesCustomizers); return customizers; } /** * 自动进行建表操作 */ class HibernateDefaultDdlAutoProvider implements SchemaManagementProvider { private final Iterable<SchemaManagementProvider> providers; HibernateDefaultDdlAutoProvider(Iterable<SchemaManagementProvider> providers) { this.providers = providers; } public String getDefaultDdlAuto(DataSource dataSource) { if (!EmbeddedDatabaseConnection.isEmbedded(dataSource)) { return "none"; } SchemaManagement schemaManagement = getSchemaManagement(dataSource); if (SchemaManagement.MANAGED.equals(schemaManagement)) { return "none"; } return "create-drop"; } @Override public SchemaManagement getSchemaManagement(DataSource dataSource) { return StreamSupport.stream(this.providers.spliterator(), false) .map((provider) -> provider.getSchemaManagement(dataSource)) .filter(SchemaManagement.MANAGED::equals).findFirst() .orElse(SchemaManagement.UNMANAGED); } } private static class NamingStrategiesHibernatePropertiesCustomizer implements HibernatePropertiesCustomizer { private final PhysicalNamingStrategy physicalNamingStrategy; private final ImplicitNamingStrategy implicitNamingStrategy; NamingStrategiesHibernatePropertiesCustomizer( PhysicalNamingStrategy physicalNamingStrategy, ImplicitNamingStrategy implicitNamingStrategy) { this.physicalNamingStrategy = physicalNamingStrategy; this.implicitNamingStrategy = implicitNamingStrategy; } /** * 数据库命名映射策略 * * @param hibernateProperties the JPA vendor properties to customize */ @Override public void customize(Map<String, Object> hibernateProperties) { if (this.physicalNamingStrategy != null) { hibernateProperties.put("hibernate.physical_naming_strategy", this.physicalNamingStrategy); } if (this.implicitNamingStrategy != null) { hibernateProperties.put("hibernate.implicit_naming_strategy", this.implicitNamingStrategy); } } } }
这里需要注意以下,配置多数据源会导致默认的配置失效(不仅仅针对JPA),然后驼峰匹配也就没得用了,
.properties(getVendorProperties(dataSource1))我在这里手动去设置了一下驼峰匹配
@Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef ="entityManagerFactoryDataBase2", transactionManagerRef = "transactionManagerDatabase2", basePackages = "com.src.dao.datasource2" ) public class DataBase2Configer { @Autowired @Qualifier(value = "dataSource2") private DataSource dataSource2; @Bean(name = "entityManagerFactoryDataBase2") public LocalContainerEntityManagerFactoryBean entityManagerFactoryDataBase2(EntityManagerFactoryBuilder builder){ return builder .dataSource(dataSource2) .packages("com.src.model.datasource2") .persistenceUnit("database2PersistenceUnit") .build(); } /** * 配置事物管理器 * * @param builder * @return */ @Bean(name = "transactionManagerDatabase2") PlatformTransactionManager transactionManagerDatabase2(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactoryDataBase2(builder).getObject()); } }
好了,这样我们的Spring data jpa整合多数据源就Ok了。。