Spring引导应用程序中的表没有在多个数据库中创建 [英] Tables not getting created in multiple databases in spring boot application
问题描述
我正在开发Spring Boot多租户应用程序。我已经配置了多个datasources,如下所示:
application.properties
spring.multitenancy.datasource1.url = jdbc:mysql:// localhost:3306 / db1
spring.multitenancy.datasource1.username = root
spring.multitenancy.datasource1.password = ****
spring.multitenancy.datasource1.driver-class-name = com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto =更新
spring.multitenancy.datasource2 .url = jdbc:mysql:// localhost:3306 / db2
spring.multitenancy.datasource2.username = root
spring.multitenancy.datasource2.password = ****
spring.multitenancy .datasource2.driver-class-name = com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto = update
spring.multitenancy.datasource3.url = jdbc:mysql :// localhost:3306 / db3
spring.multitenancy.datasource3.username = root
spring.multitenancy.datasource3.password = ****
spring.multitenancy.datasource3.driver-class -name = com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-au to = update
DataSourceBasedMultiTenantConnectionProviderImpl.java
@Component
public class DataSourceBasedMultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
private static final long serialVersionUID = 8168907057647334460L;
private static final String DEFAULT_TENANT_ID =tenant_1;
@Autowired
私有DataSource dataSource1;
@Autowired
私有DataSource dataSource2;
@Autowired
私有DataSource dataSource3;
私人地图< String,DataSource>地图;
@PostConstruct
public void load(){$ b $ map = new HashMap<>();
map.put(tenant_1,dataSource1);
map.put(tenant_2,dataSource2);
map.put(tenant_3,dataSource3);
}
@Override
protected DataSource selectAnyDataSource(){
return map.get(DEFAULT_TENANT_ID);
}
@Override
protected DataSource selectDataSource(String tenantIdentifier){
return map.get(tenantIdentifier);
$ / code> $ / pre>
MultitenancyProperties.java
@ConfigurationProperties(spring.multitenancy)
public class MultitenancyProperties {
@NestedConfigurationProperty
private DataSourceProperties datasource1 ;
@NestedConfigurationProperty
private DataSourceProperties datasource2;
@NestedConfigurationProperty
private DataSourceProperties datasource3;
public DataSourceProperties getDatasource1(){
return datasource1;
}
public void setDatasource1(DataSourceProperties datasource1){
this.datasource1 = datasource1;
}
public DataSourceProperties getDatasource2(){
return datasource2;
}
public void setDatasource2(DataSourceProperties datasource2){
this.datasource2 = datasource2;
}
public DataSourceProperties getDatasource3(){
return datasource3;
}
public void setDatasource3(DataSourceProperties datasource3){
this.datasource3 = datasource3;
$ / code>MultiTenancyJpaConfiguration.java
@Configuration
@EnableConfigurationProperties(JpaProperties.class)
public class MultiTenancyJpaConfiguration {
@Autowired
私有DataSource数据源;
@Autowired
私有JpaProperties jpaProperties;
@Autowired
私有MultiTenantConnectionProvider multiTenantConnectionProvider;
@Autowired
私人CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder){
Map< String,Object> hibernateProps = new LinkedHashMap<>();
hibernateProps.putAll(jpaProperties.getHibernateProperties(dataSource));
hibernateProps.put(Environment.MULTI_TENANT,MultiTenancyStrategy.DATABASE);
hibernateProps.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER,multiTenantConnectionProvider);
hibernateProps.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER,currentTenantIdentifierResolver);
hibernateProps.put(Environment.DIALECT,org.hibernate.dialect.MySQLDialect);
return builder.dataSource(dataSource).packages(HotelEntity.class.getPackage()。getName())。properties(hibernateProps).jta(false).build();
code
应用程序启动器
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(MultitenancyProperties.class)
public class Application {
public static void main(String [] args){
ApplicationContext ctx = SpringApplication.run(Application.class,args);
$ / code>当我运行启动应用程序时,创建所有表仅在第一个数据源中。
1)如何在应用程序启动时在所有数据源中创建表?
2)如何查看每个数据源的打开/关闭连接?
3)有没有更好的方式使用spring boot配置多租户应用程序以获得更好的性能?
解决方案正如@Alex所说的,您需要不同的EntityManagers,TransactionManager和Datasources。这是我该怎么做的。
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef =dataSource1EntityManagerFactory,
transactionManagerRef =dataSource1TransactionManager,
basePackageClasses = dataSource1Repository.class)
public class DataSource1Config extends SqlConfig {//将所有通用代码放在基类SqlConfig中。如果不删除它
@Bean
@Primary
public DataSource dataSource1(){
//使用MultitenancyProperties :: getDataSource1
创建数据源
$ b @Primary
@Bean(name =dataSource1TransactionManager)
PlatformTransactionManager dataSource1TransactionManager(EntityManagerFactory dataSource1EntityManagerFactory){
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(dataSource1EntityManagerFactory);
返回txManager;
$ b @Primary
@Bean(name =dataSource1EntityManagerFactory)
LocalContainerEntityManagerFactoryBean dataSource1EntityManagerFactory(){
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource1());
em.setPackagesToScan(dataSource1Repository.class.getPackage()。getName(),dataSource1ModelClass.class.getPackage()。getName());
em.setPersistenceUnitName(dataSource1Db);
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
em.setJpaVendorAdapter(vendorAdapter);
返回em;
$ b你可以像这样创建另外两个类。请记住仅在数据源,transactionmanger和entitymanager的一个实例上使用@Primary
(哪一个并不重要)。还有一点要小心,确保Repository类在所有三个数据库的不同包中。I am working on spring boot multi tenancy application. I have configured multi datasources as shown below :
application.properties
spring.multitenancy.datasource1.url=jdbc:mysql://localhost:3306/db1 spring.multitenancy.datasource1.username=root spring.multitenancy.datasource1.password=**** spring.multitenancy.datasource1.driver-class-name=com.mysql.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.multitenancy.datasource2.url=jdbc:mysql://localhost:3306/db2 spring.multitenancy.datasource2.username=root spring.multitenancy.datasource2.password=**** spring.multitenancy.datasource2.driver-class-name=com.mysql.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.multitenancy.datasource3.url=jdbc:mysql://localhost:3306/db3 spring.multitenancy.datasource3.username=root spring.multitenancy.datasource3.password=**** spring.multitenancy.datasource3.driver-class-name=com.mysql.jdbc.Driver spring.jpa.hibernate.ddl-auto=update
DataSourceBasedMultiTenantConnectionProviderImpl.java
@Component public class DataSourceBasedMultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl { private static final long serialVersionUID = 8168907057647334460L; private static final String DEFAULT_TENANT_ID = "tenant_1"; @Autowired private DataSource dataSource1; @Autowired private DataSource dataSource2; @Autowired private DataSource dataSource3; private Map<String, DataSource> map; @PostConstruct public void load() { map = new HashMap<>(); map.put("tenant_1", dataSource1); map.put("tenant_2", dataSource2); map.put("tenant_3", dataSource3); } @Override protected DataSource selectAnyDataSource() { return map.get(DEFAULT_TENANT_ID); } @Override protected DataSource selectDataSource(String tenantIdentifier) { return map.get(tenantIdentifier); } }
MultitenancyProperties.java
@ConfigurationProperties("spring.multitenancy") public class MultitenancyProperties { @NestedConfigurationProperty private DataSourceProperties datasource1; @NestedConfigurationProperty private DataSourceProperties datasource2; @NestedConfigurationProperty private DataSourceProperties datasource3; public DataSourceProperties getDatasource1() { return datasource1; } public void setDatasource1(DataSourceProperties datasource1) { this.datasource1 = datasource1; } public DataSourceProperties getDatasource2() { return datasource2; } public void setDatasource2(DataSourceProperties datasource2) { this.datasource2 = datasource2; } public DataSourceProperties getDatasource3() { return datasource3; } public void setDatasource3(DataSourceProperties datasource3) { this.datasource3 = datasource3; } }
MultiTenancyJpaConfiguration.java
@Configuration @EnableConfigurationProperties(JpaProperties.class) public class MultiTenancyJpaConfiguration { @Autowired private DataSource dataSource; @Autowired private JpaProperties jpaProperties; @Autowired private MultiTenantConnectionProvider multiTenantConnectionProvider; @Autowired private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) { Map<String, Object> hibernateProps = new LinkedHashMap<>(); hibernateProps.putAll(jpaProperties.getHibernateProperties(dataSource)); hibernateProps.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE); hibernateProps.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider); hibernateProps.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver); hibernateProps.put(Environment.DIALECT, "org.hibernate.dialect.MySQLDialect"); return builder.dataSource(dataSource).packages(HotelEntity.class.getPackage().getName()).properties(hibernateProps).jta(false).build(); } }
Application launcher
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @EnableConfigurationProperties(MultitenancyProperties.class) public class Application { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); } }
When I run the boot application, all tables are created in only first data source.
1) How can I create tables in all data sources on application startup?
2) How to see connections opened/closed for each of the data sources?
3) Is there a better way of configuring multi tenancy application using spring boot for better performance?解决方案As @Alex said, you need differnt EntityManagers, TransactionManager and Datasources. Here is how I would do it
@Configuration @EnableJpaRepositories( entityManagerFactoryRef = "dataSource1EntityManagerFactory", transactionManagerRef = "dataSource1TransactionManager", basePackageClasses = dataSource1Repository.class) public class DataSource1Config extends SqlConfig{// Put all common code in base class SqlConfig. If not remove it @Bean @Primary public DataSource dataSource1() { //create dataSource using MultitenancyProperties::getDataSource1 } @Primary @Bean(name = "dataSource1TransactionManager") PlatformTransactionManager dataSource1TransactionManager(EntityManagerFactory dataSource1EntityManagerFactory) { JpaTransactionManager txManager = new JpaTransactionManager(); txManager.setEntityManagerFactory(dataSource1EntityManagerFactory); return txManager; } @Primary @Bean(name = "dataSource1EntityManagerFactory") LocalContainerEntityManagerFactoryBean dataSource1EntityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource1()); em.setPackagesToScan(dataSource1Repository.class.getPackage().getName(), dataSource1ModelClass.class.getPackage().getName()); em.setPersistenceUnitName("dataSource1Db"); HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl(false); em.setJpaVendorAdapter(vendorAdapter); return em; } }
You can create two other classes like this. Remember to use
@Primary
on only one instace of datasource, transactionmanger and entitymanager(doesn't matter which one). Another word of caution, make sure Repository classes are in different packages for all three databases.这篇关于Spring引导应用程序中的表没有在多个数据库中创建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!