java – 使用Spring MVC和Hibernate在多租户数据库应用程序中动态添加租户

前端之家收集整理的这篇文章主要介绍了java – 使用Spring MVC和Hibernate在多租户数据库应用程序中动态添加租户前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在开发使用多租户数据库配置的Web应用程序.

我想动态添加租户.

添加了主控制器来创建主模式,其中包含动态创建的租户记录.

但问题是,当我请求创建租户时,它去了MultitenantConnectionProvider我在那里创建了数据库但是在数据库中我想扫描包com.appointment.schedular.model.tenant并在ne数据库中创建表.

Source code

MasterDatabaseConfig.java

  1. @Configuration
  2. @EnableTransactionManagement
  3. @EnableJpaRepositories(
  4. basePackages = "com.appointment.schedular.dao.master",entityManagerFactoryRef = "masterEntityManager",transactionManagerRef = "masterTransactionManager"
  5. )
  6. @PropertySource("classpath:application.properties")
  7. public class MasterDatabaseConfig {
  8.  
  9. @Autowired
  10. private Environment springEnvironment;
  11.  
  12. @Bean(name="masterDataSource")
  13. public DataSource masterDataSource() {
  14. DriverManagerDataSource dataSource = new DriverManagerDataSource();
  15. dataSource.setDriverClassName(springEnvironment.getProperty("master.datasource.classname"));
  16. dataSource.setUrl(springEnvironment.getProperty("master.datasource.url") + "?createDatabaseIfNotExist=true");
  17. dataSource.setUsername(springEnvironment.getProperty("master.datasource.user"));
  18. dataSource.setPassword(springEnvironment.getProperty("master.datasource.password"));
  19. return dataSource;
  20. }
  21.  
  22. @Bean(name = "masterEntityManager")
  23. @Primary
  24. public LocalContainerEntityManagerfactorybean masterEntityManagerFactory() {
  25. LocalContainerEntityManagerfactorybean entityManagerfactorybean
  26. = new LocalContainerEntityManagerfactorybean();
  27. entityManagerfactorybean.setDataSource(masterDataSource());
  28. entityManagerfactorybean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
  29. JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
  30. entityManagerfactorybean.setJpaVendorAdapter(vendorAdapter);
  31. entityManagerfactorybean.setPackagesToScan(new String[]{"com.appointment.schedular.model.master"});
  32. entityManagerfactorybean.setJpaProperties(getHibernateProperties());
  33. entityManagerfactorybean.setPersistenceUnitName("master");
  34. return entityManagerfactorybean;
  35. }
  36.  
  37. private Properties getHibernateProperties() {
  38. Properties properties = new Properties();
  39. properties.put("hibernate.dialect",springEnvironment.getProperty("hibernate.dialect","org.hibernate.dialect.MysqLDialect"));
  40. properties.put("hibernate.show_sql",springEnvironment.getProperty("hibernate.show_sql","true"));
  41. properties.put("hibernate.format_sql",springEnvironment.getProperty("hibernate.format_sql","true"));
  42. properties.put("hibernate.hbm2ddl.auto",springEnvironment.getProperty("hibernate.hbm2ddl.auto","update"));
  43. return properties;
  44. }
  45.  
  46. @Bean(name = "masterTransactionManager")
  47. public JpaTransactionManager transactionManager(EntityManagerFactory masterEntityManager) {
  48. JpaTransactionManager transactionManager = new JpaTransactionManager();
  49. transactionManager.setEntityManagerFactory(masterEntityManager);
  50. return transactionManager;
  51. }
  52. }

TenantDatabaseConfig.java

  1. @Configuration
  2. @EnableTransactionManagement
  3. @ComponentScan("com.appointment.schedular.tenant")
  4. @EnableJpaRepositories(
  5. entityManagerFactoryRef = "tenantEntityManager",transactionManagerRef = "tenantTransactionManager",basePackages = {"com.appointment.schedular.dao.tenant"})
  6. @PropertySource("classpath:application.properties")
  7. public class TenantDatabaseConfig {
  8.  
  9. @Autowired
  10. private Environment springEnvironment;
  11.  
  12. @Bean
  13. public JpaVendorAdapter jpaVendorAdapter() {
  14. return new HibernateJpaVendorAdapter();
  15. }
  16.  
  17. @Bean(name = "tenantDataSource")
  18. public DataSource tenantDataSource() {
  19. DriverManagerDataSource dataSource = new DriverManagerDataSource();
  20. dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
  21. dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url")+"xy" + "?createDatabaseIfNotExist=true");
  22. dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
  23. dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
  24. return dataSource;
  25. }
  26.  
  27. @Bean(name = "tenantEntityManager")
  28. public LocalContainerEntityManagerfactorybean entityManagerFactory(
  29. MultiTenantConnectionProvider connectionProvider,CurrentTenantIdentifierResolver tenantResolver) {
  30. LocalContainerEntityManagerfactorybean emfBean = new LocalContainerEntityManagerfactorybean();
  31.  
  32. emfBean.setDataSource(tenantDataSource());
  33. emfBean.setPackagesToScan("com.appointment.schedular.model.tenant");
  34. emfBean.setJpaVendorAdapter(jpaVendorAdapter());
  35. Map<String,Object> properties = new HashMap<>();
  36. properties.put(org.hibernate.cfg.Environment.MULTI_TENANT,MultiTenancyStrategy.SCHEMA);
  37. properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER,connectionProvider);
  38. properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER,tenantResolver);
  39. properties.put("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy");
  40. properties.put("hibernate.dialect","update"));
  41. emfBean.setJpaPropertyMap(properties);
  42. emfBean.setPersistenceUnitName("master");
  43. return emfBean;
  44. }
  45.  
  46. @Bean(name = "tenantTransactionManager")
  47. public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager) {
  48. JpaTransactionManager transactionManager = new JpaTransactionManager();
  49. transactionManager.setEntityManagerFactory(tenantEntityManager);
  50. return transactionManager;
  51. }
  52. }

MultitenantConnectionProviderImpl.java

  1. @SuppressWarnings("serial")
  2. @Component
  3. @PropertySource("classpath:application.properties")
  4. public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl implements ApplicationListener<ContextRefreshedEvent> {
  5.  
  6. @Autowired
  7. private Environment springEnvironment;
  8.  
  9. @Autowired
  10. private TenantDao tenantDao;
  11.  
  12. @Autowired
  13. @Qualifier("tenantDataSource")
  14. DataSource masterDataSource;
  15.  
  16. /*@Autowired
  17. @Qualifier("tenantEntityManager")
  18. EntityManager*/
  19.  
  20. private final Map<String,DataSource> map = new HashMap<>();
  21.  
  22. @Override
  23. public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
  24. init();
  25. }
  26.  
  27. private void init() {
  28. List<Tenant> tenants = tenantDao.findAll();
  29. for (Tenant tenant : tenants) {
  30. DataSource genDatasource = constructDataSource(tenant.getTenantKey());
  31. map.put(tenant.getTenantKey(),genDatasource);
  32.  
  33. /*
  34. LocalContainerEntityManagerfactorybean entityManagerfactorybean
  35. = new LocalContainerEntityManagerfactorybean();
  36. entityManagerfactorybean.setDataSource(genDatasource);
  37. entityManagerfactorybean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
  38. JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
  39. entityManagerfactorybean.setJpaVendorAdapter(vendorAdapter);
  40. entityManagerfactorybean.setPackagesToScan(new String[]{"com.appointment.schedular.model.tenant"});
  41.  
  42. Map<String,Object> properties = new HashMap<>();
  43. properties.put("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy");
  44. properties.put("hibernate.dialect","org.hibernate.dialect.MysqLDialect"));
  45. properties.put("hibernate.show_sql","true"));
  46. properties.put("hibernate.format_sql","true"));
  47. properties.put("hibernate.hbm2ddl.auto","update"));
  48.  
  49. entityManagerfactorybean.setJpaPropertyMap(properties);
  50. */
  51. }
  52. }
  53.  
  54. private DataSource constructDataSource(String dbName) {
  55. DriverManagerDataSource dataSource = new DriverManagerDataSource();
  56. dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
  57. dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url") + dbName+ "?createDatabaseIfNotExist=true");
  58. dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
  59. dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
  60. try {
  61. dataSource.getConnection().createStatement().execute("CREATE DATABASE IF NOT EXISTS " + dbName);
  62. } catch (Exception ex) {
  63. System.out.println(ex);
  64. }
  65. return dataSource;
  66. }
  67.  
  68. @Override
  69. protected DataSource selectAnyDataSource() {
  70. return masterDataSource;
  71. }
  72.  
  73. @Override
  74. protected DataSource selectDataSource(String key) {
  75. return map.get(key);
  76. }
  77.  
  78. public void addTenant(String tenantKey) {
  79. map.put(tenantKey,constructDataSource(tenantKey));
  80. }
  81. }

TenantController.java

  1. @Controller
  2. @RequestMapping("/tenant")
  3. public class TenantController {
  4.  
  5. @Autowired
  6. TenantDao tenantRepo;
  7.  
  8. @Autowired
  9. MultiTenantConnectionProviderImpl multiTenantConnectionProviderImpl;
  10.  
  11.  
  12. @SuppressWarnings("rawtypes")
  13. @CrossOrigin
  14. @RequestMapping(value = "/",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
  15. public @ResponseBody String registerTenant(@RequestBody Map map) throws JsonProcessingException {
  16.  
  17. ObjectMapper mapper = new ObjectMapper();
  18. Tenant tenant = mapper.convertValue(map,Tenant.class);
  19.  
  20. String tenantKey = tenant.getName().replaceAll("[^a-zA-Z]+","").toLowerCase().trim();
  21. Optional<Tenant> prevIoUslyStored = tenantRepo.findByTenantKey(tenantKey);
  22. String response="Sorry your company name ("+tenant.getName()+")"+" is already taken";
  23. if (!prevIoUslyStored.isPresent()) {
  24. tenant.setTenantKey(tenantKey);
  25. tenantRepo.save(tenant);
  26. multiTenantConnectionProviderImpl.addTenant(tenantKey);
  27. response = "Successfully registered,your key is " + tenantKey;
  28. return response;
  29. }
  30. return new ObjectMapper().writeValueAsString(response);
  31. }
  32. }

解决方法

用此代码替换您的MultitenantConnectionProviderImpl.java.使用注入服务使用配置类创建表.
  1. @SuppressWarnings("serial")
  2. @Component
  3. @PropertySource("classpath:application.properties")
  4. public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl implements ApplicationListener<ContextRefreshedEvent>,ServiceRegistryAwareService {
  5.  
  6. @Autowired
  7. private Environment springEnvironment;
  8.  
  9. @Autowired
  10. private TenantDao tenantDao;
  11.  
  12. @Autowired
  13. @Qualifier("dataSource1")
  14. DataSource masterDataSource;
  15.  
  16. @Autowired
  17. MultiTenantConnectionProvider connectionProvider;
  18.  
  19. @Autowired
  20. CurrentTenantIdentifierResolver tenantResolver;
  21.  
  22. @Autowired
  23. TenantDatabaseConfig tenantDatabaseConfig;
  24.  
  25.  
  26. private final Map<String,DataSource> map = new HashMap<>();
  27.  
  28. @Override
  29. public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
  30. init();
  31. }
  32.  
  33. private void init() {
  34. List<Tenant> tenants = tenantDao.findAll();
  35. for (Tenant tenant : tenants) {
  36. map.put(tenant.getTenantKey(),constructDataSource(tenant.getTenantKey()));
  37. }
  38. }
  39.  
  40. private DataSource constructDataSource(String dbName) {
  41. DriverManagerDataSource dataSource = new DriverManagerDataSource();
  42. dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
  43. dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url") + dbName+"?createDatabaseIfNotExist=true");
  44. dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
  45. dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
  46.  
  47. entityManagerFactory(dataSource,connectionProvider,tenantResolver);
  48.  
  49.  
  50. return dataSource;
  51. }
  52.  
  53. public LocalContainerEntityManagerfactorybean entityManagerFactory(DataSource dataSource,MultiTenantConnectionProvider connectionProvider,CurrentTenantIdentifierResolver tenantResolver) {
  54. LocalContainerEntityManagerfactorybean emfBean = new LocalContainerEntityManagerfactorybean();
  55. emfBean.setDataSource(dataSource);
  56. emfBean.setPackagesToScan("com.appointment.schedular.model.tenant");
  57. emfBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
  58. emfBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
  59. Map<String,MultiTenancyStrategy.DATABASE);
  60. properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER,"update"));
  61. emfBean.setJpaPropertyMap(properties);
  62. emfBean.setPersistenceUnitName(dataSource.toString());
  63. emfBean.afterPropertiesSet();
  64. //emfBean.setEntityManagerFactoryInterface((EntityMana)emfBean);
  65. //emfBean.setBeanName("srgsrohtak");
  66. return emfBean;
  67. }
  68.  
  69. public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager) {
  70. JpaTransactionManager transactionManager = new JpaTransactionManager();
  71. transactionManager.setEntityManagerFactory(tenantEntityManager);
  72. transactionManager.afterPropertiesSet();
  73. return transactionManager;
  74. }
  75.  
  76. @Override
  77. public void injectServices(ServiceRegistryImplementor serviceRegistry) {
  78. Map lSettings = serviceRegistry.getService(ConfigurationService.class).getSettings();
  79. DataSource localDs = (DataSource) lSettings.get("hibernate.connection.datasource");
  80. masterDataSource = localDs;
  81. }
  82.  
  83. @Override
  84. protected DataSource selectAnyDataSource() {
  85. return masterDataSource;
  86. }
  87.  
  88. @Override
  89. protected DataSource selectDataSource(String key) {
  90. return map.get(key);
  91. }
  92.  
  93. public void addTenant(String tenantKey) {
  94. map.put(tenantKey,constructDataSource(tenantKey));
  95. }
  96. }

猜你在找的Java相关文章