По сути, я хочу запустить приложение с основным источником данных tenant1 с таблицей person, то после развертывания я хочу динамически добавить еще один источник данных tenant2, который также содержит таблицу person.
Я создал 1 база данных по умолчанию выглядит следующим образом:
Код: Выделить всё
Tenant 1: url: jdbc:mysql://localhost:3307/primarydb
Код: Выделить всё
spring:
application:
name: dynamic-demo-db
main:
allow-bean-definition-overriding: true
dynamic:
datasources:
tenant1:
url: jdbc:mysql://localhost:3307/primarydb
username: root
password: root
driverClassName: com.mysql.cj.jdbc.Driver
Код: Выделить всё
@Component
@ConfigurationProperties(prefix = "dynamic")
public class DynamicDataSourceProperties {
private Map datasources;
public Map getDatasources() {
return datasources;
}
public void setDatasources(Map datasources) {
this.datasources = datasources;
}
}
Код: Выделить всё
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return TenantContext.getCurrentTenant();
}
}
Код: Выделить всё
public class TenantContext {
private static final ThreadLocal CONTEXT = new ThreadLocal();
public static void setCurrentTenant(String tenantId) {
CONTEXT.set(tenantId);
}
public static String getCurrentTenant() {
return CONTEXT.get();
}
public static void clear() {
CONTEXT.remove();
}
}
Код: Выделить всё
@Configuration
public class DynamicDataSourceConfig {
@Autowired
private DynamicDataSourceProperties properties;
private Map dataSourceMap = new ConcurrentHashMap();
@Bean
public DataSource dataSource() {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
properties.getDatasources().forEach((key, dataSourceProperties) -> {
HikariDataSource dataSource = createDataSource(dataSourceProperties);
dataSourceMap.put(key, dataSource);
});
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
dynamicRoutingDataSource.setDefaultTargetDataSource(dataSourceMap.values().iterator().next());
return dynamicRoutingDataSource;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
public void addDataSource(String key, DataSourceProperties dataSourceProperties) {
HikariDataSource dataSource = createDataSource(dataSourceProperties);
dataSourceMap.put(key, dataSource);
((DynamicRoutingDataSource) dataSource()).setTargetDataSources(dataSourceMap);
((DynamicRoutingDataSource) dataSource()).afterPropertiesSet(); // Refresh the DataSource routing
}
private HikariDataSource createDataSource(DataSourceProperties properties) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(properties.getDriverClassName());
dataSource.setJdbcUrl(properties.getUrl());
dataSource.setUsername(properties.getUsername());
dataSource.setPassword(properties.getPassword());
return dataSource;
}
}
Код: Выделить всё
@Service
public class DataSourceService {
@Autowired
private DynamicDataSourceConfig dynamicDataSourceConfig;
@Autowired
PersonRepository personRepository;
public void addDataSource(String key, DataSourceProperties properties) {
dynamicDataSourceConfig.addDataSource(key, properties);
}
@Transactional
public Person savePerson(PersonRequest personRequest) {
DataSourceContextHolder.setDataSourceKey(personRequest.getDatasource());
return personRepository.save(personRequest.getPerson());
}
Код: Выделить всё
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.sql.DataSource;
import java.sql.SQLException;
@RestController
@RequestMapping("/datasource")
public class DataSourceController {
@Autowired
private DataSourceService dataSourceService;
@Autowired
DataSource dataSource;
@PostMapping("/add")
public void addDataSource(@RequestParam String key,
@RequestParam String url,
@RequestParam String username,
@RequestParam String password,
@RequestParam String driverClassName) throws SQLException {
DataSourceProperties properties = new DataSourceProperties();
properties.setUrl(url);
properties.setUsername(username);
properties.setPassword(password);
properties.setDriverClassName(driverClassName);
dataSourceService.addDataSource(key, properties);
dataSource.getConnection();
}
@PostMapping("/addPerson")
public Person savePerson(@RequestBody PersonRequest personRequest) {
return dataSourceService.savePerson(personRequest);
}
}
}
Вышеуказанный источник данных успешно добавлен, и результат addPerson для ново созданной базы данных показан ниже:

Однако запись вставлена в tenant1(primarydb ) вместо tenant2(вторичный db).
Похоже, даже если я добавил tenant2 с новой базой данных, он не принимается во внимание.
Записи сохраняются в источнике данных по умолчанию — tenant1.
Пожалуйста, подскажите, что я делаю не так?
Подробнее здесь: https://stackoverflow.com/questions/786 ... boot-3-3-0
Мобильная версия