我正在开发使用多租户数据库配置的Web应用程序.
我想动态添加租户.
我添加了主控制器来创建主模式,其中包含动态创建的租户记录.
但问题是,当我请求创建租户时,它去了MultitenantConnectionProvider我在那里创建了数据库但是在数据库中我想扫描包com.appointment.schedular.model.tenant并在ne数据库中创建表.
MasterDatabaseConfig.java
@Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = "com.appointment.schedular.dao.master",entityManagerFactoryRef = "masterEntityManager",transactionManagerRef = "masterTransactionManager" ) @PropertySource("classpath:application.properties") public class MasterDatabaseConfig { @Autowired private Environment springEnvironment; @Bean(name="masterDataSource") public DataSource masterDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(springEnvironment.getProperty("master.datasource.classname")); dataSource.setUrl(springEnvironment.getProperty("master.datasource.url") + "?createDatabaseIfNotExist=true"); dataSource.setUsername(springEnvironment.getProperty("master.datasource.user")); dataSource.setPassword(springEnvironment.getProperty("master.datasource.password")); return dataSource; } @Bean(name = "masterEntityManager") @Primary public LocalContainerEntityManagerfactorybean masterEntityManagerFactory() { LocalContainerEntityManagerfactorybean entityManagerfactorybean = new LocalContainerEntityManagerfactorybean(); entityManagerfactorybean.setDataSource(masterDataSource()); entityManagerfactorybean.setPersistenceProviderClass(HibernatePersistenceProvider.class); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); entityManagerfactorybean.setJpaVendorAdapter(vendorAdapter); entityManagerfactorybean.setPackagesToScan(new String[]{"com.appointment.schedular.model.master"}); entityManagerfactorybean.setJpaProperties(getHibernateProperties()); entityManagerfactorybean.setPersistenceUnitName("master"); return entityManagerfactorybean; } private Properties getHibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.dialect",springEnvironment.getProperty("hibernate.dialect","org.hibernate.dialect.MysqLDialect")); properties.put("hibernate.show_sql",springEnvironment.getProperty("hibernate.show_sql","true")); properties.put("hibernate.format_sql",springEnvironment.getProperty("hibernate.format_sql","true")); properties.put("hibernate.hbm2ddl.auto",springEnvironment.getProperty("hibernate.hbm2ddl.auto","update")); return properties; } @Bean(name = "masterTransactionManager") public JpaTransactionManager transactionManager(EntityManagerFactory masterEntityManager) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(masterEntityManager); return transactionManager; } }
TenantDatabaseConfig.java
@Configuration @EnableTransactionManagement @ComponentScan("com.appointment.schedular.tenant") @EnableJpaRepositories( entityManagerFactoryRef = "tenantEntityManager",transactionManagerRef = "tenantTransactionManager",basePackages = {"com.appointment.schedular.dao.tenant"}) @PropertySource("classpath:application.properties") public class TenantDatabaseConfig { @Autowired private Environment springEnvironment; @Bean public JpaVendorAdapter jpaVendorAdapter() { return new HibernateJpaVendorAdapter(); } @Bean(name = "tenantDataSource") public DataSource tenantDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname")); dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url")+"xy" + "?createDatabaseIfNotExist=true"); dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user")); dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password")); return dataSource; } @Bean(name = "tenantEntityManager") public LocalContainerEntityManagerfactorybean entityManagerFactory( MultiTenantConnectionProvider connectionProvider,CurrentTenantIdentifierResolver tenantResolver) { LocalContainerEntityManagerfactorybean emfBean = new LocalContainerEntityManagerfactorybean(); emfBean.setDataSource(tenantDataSource()); emfBean.setPackagesToScan("com.appointment.schedular.model.tenant"); emfBean.setJpaVendorAdapter(jpaVendorAdapter()); Map<String,Object> properties = new HashMap<>(); properties.put(org.hibernate.cfg.Environment.MULTI_TENANT,MultiTenancyStrategy.SCHEMA); properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER,connectionProvider); properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER,tenantResolver); properties.put("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy"); properties.put("hibernate.dialect","update")); emfBean.setJpaPropertyMap(properties); emfBean.setPersistenceUnitName("master"); return emfBean; } @Bean(name = "tenantTransactionManager") public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(tenantEntityManager); return transactionManager; } }
MultitenantConnectionProviderImpl.java
@SuppressWarnings("serial") @Component @PropertySource("classpath:application.properties") public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl implements ApplicationListener<ContextRefreshedEvent> { @Autowired private Environment springEnvironment; @Autowired private TenantDao tenantDao; @Autowired @Qualifier("tenantDataSource") DataSource masterDataSource; /*@Autowired @Qualifier("tenantEntityManager") EntityManager*/ private final Map<String,DataSource> map = new HashMap<>(); @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { init(); } private void init() { List<Tenant> tenants = tenantDao.findAll(); for (Tenant tenant : tenants) { DataSource genDatasource = constructDataSource(tenant.getTenantKey()); map.put(tenant.getTenantKey(),genDatasource); /* LocalContainerEntityManagerfactorybean entityManagerfactorybean = new LocalContainerEntityManagerfactorybean(); entityManagerfactorybean.setDataSource(genDatasource); entityManagerfactorybean.setPersistenceProviderClass(HibernatePersistenceProvider.class); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); entityManagerfactorybean.setJpaVendorAdapter(vendorAdapter); entityManagerfactorybean.setPackagesToScan(new String[]{"com.appointment.schedular.model.tenant"}); Map<String,Object> properties = new HashMap<>(); properties.put("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy"); properties.put("hibernate.dialect","org.hibernate.dialect.MysqLDialect")); properties.put("hibernate.show_sql","true")); properties.put("hibernate.format_sql","true")); properties.put("hibernate.hbm2ddl.auto","update")); entityManagerfactorybean.setJpaPropertyMap(properties); */ } } private DataSource constructDataSource(String dbName) { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname")); dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url") + dbName+ "?createDatabaseIfNotExist=true"); dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user")); dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password")); try { dataSource.getConnection().createStatement().execute("CREATE DATABASE IF NOT EXISTS " + dbName); } catch (Exception ex) { System.out.println(ex); } return dataSource; } @Override protected DataSource selectAnyDataSource() { return masterDataSource; } @Override protected DataSource selectDataSource(String key) { return map.get(key); } public void addTenant(String tenantKey) { map.put(tenantKey,constructDataSource(tenantKey)); } }
TenantController.java
@Controller @RequestMapping("/tenant") public class TenantController { @Autowired TenantDao tenantRepo; @Autowired MultiTenantConnectionProviderImpl multiTenantConnectionProviderImpl; @SuppressWarnings("rawtypes") @CrossOrigin @RequestMapping(value = "/",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE) public @ResponseBody String registerTenant(@RequestBody Map map) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); Tenant tenant = mapper.convertValue(map,Tenant.class); String tenantKey = tenant.getName().replaceAll("[^a-zA-Z]+","").toLowerCase().trim(); Optional<Tenant> prevIoUslyStored = tenantRepo.findByTenantKey(tenantKey); String response="Sorry your company name ("+tenant.getName()+")"+" is already taken"; if (!prevIoUslyStored.isPresent()) { tenant.setTenantKey(tenantKey); tenantRepo.save(tenant); multiTenantConnectionProviderImpl.addTenant(tenantKey); response = "Successfully registered,your key is " + tenantKey; return response; } return new ObjectMapper().writeValueAsString(response); } }
解决方法
用此代码替换您的MultitenantConnectionProviderImpl.java.使用注入服务使用配置类创建表.
@SuppressWarnings("serial") @Component @PropertySource("classpath:application.properties") public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl implements ApplicationListener<ContextRefreshedEvent>,ServiceRegistryAwareService { @Autowired private Environment springEnvironment; @Autowired private TenantDao tenantDao; @Autowired @Qualifier("dataSource1") DataSource masterDataSource; @Autowired MultiTenantConnectionProvider connectionProvider; @Autowired CurrentTenantIdentifierResolver tenantResolver; @Autowired TenantDatabaseConfig tenantDatabaseConfig; private final Map<String,DataSource> map = new HashMap<>(); @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { init(); } private void init() { List<Tenant> tenants = tenantDao.findAll(); for (Tenant tenant : tenants) { map.put(tenant.getTenantKey(),constructDataSource(tenant.getTenantKey())); } } private DataSource constructDataSource(String dbName) { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname")); dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url") + dbName+"?createDatabaseIfNotExist=true"); dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user")); dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password")); entityManagerFactory(dataSource,connectionProvider,tenantResolver); return dataSource; } public LocalContainerEntityManagerfactorybean entityManagerFactory(DataSource dataSource,MultiTenantConnectionProvider connectionProvider,CurrentTenantIdentifierResolver tenantResolver) { LocalContainerEntityManagerfactorybean emfBean = new LocalContainerEntityManagerfactorybean(); emfBean.setDataSource(dataSource); emfBean.setPackagesToScan("com.appointment.schedular.model.tenant"); emfBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); emfBean.setPersistenceProviderClass(HibernatePersistenceProvider.class); Map<String,MultiTenancyStrategy.DATABASE); properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER,"update")); emfBean.setJpaPropertyMap(properties); emfBean.setPersistenceUnitName(dataSource.toString()); emfBean.afterPropertiesSet(); //emfBean.setEntityManagerFactoryInterface((EntityMana)emfBean); //emfBean.setBeanName("srgsrohtak"); return emfBean; } public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(tenantEntityManager); transactionManager.afterPropertiesSet(); return transactionManager; } @Override public void injectServices(ServiceRegistryImplementor serviceRegistry) { Map lSettings = serviceRegistry.getService(ConfigurationService.class).getSettings(); DataSource localDs = (DataSource) lSettings.get("hibernate.connection.datasource"); masterDataSource = localDs; } @Override protected DataSource selectAnyDataSource() { return masterDataSource; } @Override protected DataSource selectDataSource(String key) { return map.get(key); } public void addTenant(String tenantKey) { map.put(tenantKey,constructDataSource(tenantKey)); } }