В конце концов, нам просто нужен источник данных, который будет маршрутизироваться в соответствии с ситуацией.Для этого используется @Component
, который расширяет AbstractRoutingDataSource
, и ThreadLocal
для хранения контекста запроса.
ThreadLocal
будет выглядеть примерно так (примеры используют Lombok)
@AllArgsConstructor
public class UserContext {
private static final ThreadLocal<UserContext> context =
new ThreadLocal<>();
private final String schema;
public static String getSchema() {
return context.get().schema;
}
public static void setFromXXX(...) {
context.set(new UserContext(
...
));
}
}
Потребуется источник данных:
@Configuration
public class DataSources {
@Bean
public DataSource schema1() {
return build("schema1");
}
@Bean
public DataSource schema2() {
return build("schema2");
}
private DataSource buildDataSource(String schema) {
...
return new DriverManagerDataSource(url, username, password);
}
}
И, наконец, маршрутизатор, помеченный как источник данных @Primary
, чтобы убедиться, что он используется JPA..
@Component
@Primary
public class RoutingDatasource extends AbstractRoutingDataSource {
@Autowired
@Qualifier("schema1")
private DataSource schema1;
@Autowired
@Qualifier("schema2")
private DataSource schema2;
@Override
public void afterPropertiesSet() {
setTargetDataSources(
Map.of(
"schema1", schema1,
"schema2", schema2
)
);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return UserContext.getSchema();
}
}
Это позволяет избежать дублирования кода, когда все, что отличается, - это схема или даже источник данных.