我是Sping Boot 的新手,正在尝试使用Spring Boot 2、Hibernate和Flyway来实现多租户架构。我参考了教程https://reflectoring.io/flyway-spring-boot-multitenancy/来理解概念,并能够实现所提到的架构。
但是,如果我添加了一个新的字段实体类,那么一切都会中断,因为Hibernate不会在租户数据库中创建新字段。从阅读理论和stackoverflow问题中,我明白flyway是为了解决这个问题。然而,我并没有能力让它工作。
我的要求是-当我向实体类添加一个新字段时,所有租户数据库中的所有表都应该用该字段进行更新。
应用程序属性
spring:
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
flyway:
enabled: false
tenants:
datasources:
vw:
jdbcUrl: jdbc:mysql://localhost:3306/vw
driverClassName: com.mysql.jdbc.Driver
username: vikky
password: Test@123
bmw:
jdbcUrl: jdbc:mysql://localhost:3306/bmw
driverClassName: com.mysql.jdbc.Driver
username: vikky
password: Test@123
数据源配置
@Configuration
public class DataSourceConfiguration {
private final DataSourceProperties dataSourceProperties;
public DataSourceConfiguration(DataSourceProperties dataSourceProperties) {
this.dataSourceProperties = dataSourceProperties;
}
@Bean
public DataSource dataSource() {
TenantRoutingDataSource customDataSource = new TenantRoutingDataSource();
customDataSource.setTargetDataSources(dataSourceProperties.getDatasources());
return customDataSource;
}
@PostConstruct
public void migrate() {
dataSourceProperties
.getDatasources()
.values()
.stream()
.map(dataSource -> (DataSource) dataSource)
.forEach(this::migrate);
}
private void migrate(DataSource dataSource) {
Flyway flyway = Flyway.configure().dataSource(dataSource).load();
flyway.migrate();
}
}
数据源属性
@Component
@ConfigurationProperties(prefix = "tenants")
public class DataSourceProperties {
private Map<Object, Object> datasources = new LinkedHashMap<>();
public Map<Object, Object> getDatasources() {
return datasources;
}
public void setDatasources(Map<String, Map<String, String>> datasources) {
datasources
.forEach((key, value) -> this.datasources.put(key, convert(value)));
}
public DataSource convert(Map<String, String> source) {
return DataSourceBuilder.create()
.url(source.get("jdbcUrl"))
.driverClassName(source.get("driverClassName"))
.username(source.get("username"))
.password(source.get("password"))
.build();
}
}
租户路由数据源
public class TenantRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return ThreadTenantStorage.getTenantId();
}
}
标头拦截器
@Component
public class HeaderTenantInterceptor implements WebRequestInterceptor {
public static final String TENANT_HEADER = "X-tenant";
@Override
public void preHandle(WebRequest request) throws Exception {
ThreadTenantStorage.setTenantId(request.getHeader(TENANT_HEADER));
}
@Override
public void postHandle(WebRequest request, ModelMap model) throws Exception {
ThreadTenantStorage.clear();
}
@Override
public void afterCompletion(WebRequest request, Exception ex) throws Exception {
}
}
还有其他类,如Web配置,控制器等,但我不需要他们张贴在这里。
1条答案
按热度按时间8oomwypt1#
经过大量的研究,我了解到flyway只在生产的情况下需要,在这种情况下我们不想使用ddl-auto=true更新表定义。由于我不是这种情况,我添加了下面的配置,以根据实体结构更新所有模式