diff --git a/README.md b/README.md new file mode 100644 index 0000000..9e76ef1 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +## SpringBoot 2.x Configure Two DataSources Demo Project +SpringBoot 2.x Configure Two DataSources (base version 2.1.3) + +You should configure your own database connection address, the connection address in the project has expired! + +Study record:[SpringBoot2.x Data JPA 多数据源爬坑](https://blog.fjy8018.top/index.php/archives/202/) + + +## SpringBoot 2.x 多数据源配置样例工程 +SpringBoot 2.x 多数据源配置样例工程,基于SpringBoot 2.1.3版本有效 + +注意配置自己的数据库连接地址,工程内的连接地址已经失效 + +爬坑过程:[SpringBoot2.x Data JPA 多数据源爬坑](https://blog.fjy8018.top/index.php/archives/202/) \ No newline at end of file diff --git a/ReadMe.md b/ReadMe.md deleted file mode 100644 index f85f8e4..0000000 --- a/ReadMe.md +++ /dev/null @@ -1,5 +0,0 @@ -## SpringBoot 2.x Configure Two DataSources Demo Project -SpringBoot 2.x Configure Two DataSources (base version 2.1.3) - -You should configure your own database connection address, the connection address in the project has expired! -注意配置自己的数据库连接地址,工程内的连接地址已经失效 \ No newline at end of file diff --git a/src/main/java/top/fjy8018/jpadatasource/config/DataAccessConfig.java b/src/main/java/top/fjy8018/jpadatasource/config/DataAccessConfig.java index 870a5e0..8ae2764 100644 --- a/src/main/java/top/fjy8018/jpadatasource/config/DataAccessConfig.java +++ b/src/main/java/top/fjy8018/jpadatasource/config/DataAccessConfig.java @@ -1,23 +1,45 @@ package top.fjy8018.jpadatasource.config; import com.zaxxer.hikari.HikariDataSource; +import org.hibernate.boot.model.naming.ImplicitNamingStrategy; +import org.hibernate.boot.model.naming.PhysicalNamingStrategy; +import org.hibernate.cfg.AvailableSettings; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties; +import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; +import org.springframework.boot.jdbc.SchemaManagement; +import org.springframework.boot.jdbc.SchemaManagementProvider; 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.hibernate5.SpringBeanContainer; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.util.ClassUtils; import top.fjy8018.jpadatasource.entity.backup.Order; import top.fjy8018.jpadatasource.entity.primary.Product; import top.fjy8018.jpadatasource.repository.backup.OrderRepository; import top.fjy8018.jpadatasource.repository.primary.ProductRepository; import javax.sql.DataSource; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; /** * @author F嘉阳 @@ -25,6 +47,32 @@ import javax.sql.DataSource; */ @Configuration public class DataAccessConfig { + + private final ObjectProvider providers; + + private final HibernateProperties hibernateProperties; + + private final JpaProperties properties; + + private final ObjectProvider physicalNamingStrategy; + + private final ObjectProvider implicitNamingStrategy; + + private final ConfigurableListableBeanFactory beanFactory; + + private final ObjectProvider hibernatePropertiesCustomizers; + + @Autowired + public DataAccessConfig(ObjectProvider providers, HibernateProperties hibernateProperties, JpaProperties properties, ObjectProvider physicalNamingStrategy, ObjectProvider implicitNamingStrategy, ConfigurableListableBeanFactory beanFactory, ObjectProvider hibernatePropertiesCustomizers) { + this.providers = providers; + this.hibernateProperties = hibernateProperties; + this.properties = properties; + this.physicalNamingStrategy = physicalNamingStrategy; + this.implicitNamingStrategy = implicitNamingStrategy; + this.beanFactory = beanFactory; + this.hibernatePropertiesCustomizers = hibernatePropertiesCustomizers; + } + @Bean @Primary @ConfigurationProperties("spring.datasource.first") @@ -59,6 +107,8 @@ public class DataAccessConfig { EntityManagerFactoryBuilder builder, @Qualifier("firstDataSource") DataSource dataSource) { return builder .dataSource(dataSource) + // 加入规约配置 + .properties(getVendorProperties(dataSource)) .packages(Product.class) .persistenceUnit("first") .build(); @@ -69,6 +119,7 @@ public class DataAccessConfig { EntityManagerFactoryBuilder builder, @Qualifier("secondDataSource") DataSource dataSource) { return builder .dataSource(dataSource) + .properties(getVendorProperties(dataSource)) .packages(Order.class) .persistenceUnit("second") .build(); @@ -96,5 +147,123 @@ public class DataAccessConfig { entityManagerFactoryRef = "secondEntityManagerFactory", transactionManagerRef = "backupTransactionManager") public class secondConfiguration { } + + /** + * 获取配置文件信息 + * + * @param dataSource + * @return + */ + private Map getVendorProperties(DataSource dataSource) { + List hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers( + physicalNamingStrategy.getIfAvailable(), + implicitNamingStrategy.getIfAvailable(), beanFactory, + this.hibernatePropertiesCustomizers.orderedStream() + .collect(Collectors.toList())); + Supplier 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 determineHibernatePropertiesCustomizers( + PhysicalNamingStrategy physicalNamingStrategy, + ImplicitNamingStrategy implicitNamingStrategy, + ConfigurableListableBeanFactory beanFactory, + List hibernatePropertiesCustomizers) { + List 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 providers; + + HibernateDefaultDdlAutoProvider(Iterable 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 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); + } + } + } + + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7417067..3d26e7a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -23,5 +23,4 @@ spring: properties: hibernate: format_sql: true - use_sql_comments: true - generate-ddl: true \ No newline at end of file + use_sql_comments: true \ No newline at end of file