我们的mariadb数据库将面临大量数据。为了克服备份和ddl操作的问题,我们想到了将数据存储到多个数据库中的想法。基本上,我们将拥有一个包含短期数据(例如,最近30天,名为short_term)的数据库,另一个具有其余数据(名为long_term)的数据库。显然,数据需要从短期移到长期,但这应该是可以实现的。
我目前在原型上面临的问题是,我可以连接到short_term,但是如果例如要查询它们两者(例如get(),我无法在其中找到它),则无法切换到long_term。短期数据库)。
我已经这样设置了(两者都是独立工作,但不能与切换数据库上下文一起工作):
HistoryAwareRoutingSource:
public class HistoryAwareRoutingSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return ThreadLocalStorage.getDatabaseType();
}
}
ThreadLocalStorage
public class ThreadLocalStorage {
private static ThreadLocal<String> databaseType = new ThreadLocal<>();
public static void setDatabaseType(String databaseTypeName) {
databaseType.set(databaseTypeName);
}
public static String getDatabaseType() {
return databaseType.get();
}
}
DatasourceConfiguration
@Configuration
public class DatasourceConfiguration {
@Value("${spring.datasource.url}")
private String db1Url;
@Value("${spring.datasource.username}")
private String db1Username;
@Value("${spring.datasource.password}")
private String db1Password;
@Value("${spring.datasource.driver-class-name}")
private String db1DriverClassName;
@Value("${spring.datasource.connectionProperties}")
private String db1ConnectionProps;
@Value("${spring.datasource.sqlScriptEncoding}")
private String db1Encoding;
@Value("${spring.datasource2.url}")
private String db2Url;
@Value("${spring.datasource2.username}")
private String db2Username;
@Value("${spring.datasource2.password}")
private String db2Password;
@Value("${spring.datasource2.driver-class-name}")
private String db2DriverClassName;
@Value("${spring.datasource2.connectionProperties}")
private String db2ConnectionProps;
@Value("${spring.datasource2.sqlScriptEncoding}")
private String db2Encoding;
@Bean
public DataSource dataSource() {
HistoryAwareRoutingSource historyAwareRoutingSource = new HistoryAwareRoutingSource();
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put("PRIMARY", dataSource1());
dataSourceMap.put("SECONDARY", dataSource2());
historyAwareRoutingSource.setDefaultTargetDataSource(dataSource1());
historyAwareRoutingSource.setTargetDataSources(dataSourceMap);
historyAwareRoutingSource.afterPropertiesSet();
return historyAwareRoutingSource;
}
private DataSource dataSource1() {
HikariDataSource primary = new HikariDataSource();
primary.setInitializationFailTimeout(0);
primary.setMaximumPoolSize(5);
primary.setDriverClassName(db1DriverClassName);
primary.setJdbcUrl(db1Url);
primary.setUsername(db1Username);
primary.setPassword(db1Password);
primary.addDataSourceProperty("connectionProperties", db1ConnectionProps);
primary.addDataSourceProperty("sqlScriptEncoding", db1Encoding);
return primary;
}
private DataSource dataSource2() {
HikariDataSource secondary = new HikariDataSource();
secondary.setInitializationFailTimeout(0);
secondary.setMaximumPoolSize(5);
secondary.setDriverClassName(db2DriverClassName);
secondary.setJdbcUrl(db2Url);
secondary.setUsername(db2Username);
secondary.setPassword(db2Password);
secondary.addDataSourceProperty("connectionProperties", db2ConnectionProps);
secondary.addDataSourceProperty("sqlScriptEncoding", db2Encoding);
return secondary;
}
}
然后我有一个像这样的RestController类:
@RestController
@RequestMapping(value = "/story")
@RequiredArgsConstructor
public class MultiDBController {
@Autowired
private StoryService storyService;
@GetMapping("/create")
@UsePrimaryStorage
public ResponseEntity<StoryDTO> createEntity() {
setPrimaryDB();
return ResponseEntity.ok(storyService.createOne());
}
private void setPrimaryDB() {
// TODO destroy the current db connection or hand it back to the pool so the next time a connect is taken it is the PRIMARY Datasource?
ThreadLocalStorage.setDatabaseType("PRIMARY");
}
private void setSecondaryDB() {
// TODO destroy the current db connection or hand it back to the pool so the next time a connect is taken it is the PRIMARY Datasource?
ThreadLocalStorage.setDatabaseType("SECONDARY");
}
@GetMapping("/{storyId}")
public ResponseEntity<StoryDTO> get(@PathVariable UUID storyId) {
// try to find in primary db
setPrimaryDB();
Optional<StoryDTO> storyOptional = storyService.findOne(storyId);
if (!storyOptional.isPresent()) {
setSecondaryDB();
Optional<StoryDTO> storyOptionalSecondary = storyService.findOne(storyId);
if(storyOptionalSecondary.isPresent()) {
return ResponseEntity.ok(storyOptionalSecondary.get());
} else {
return ResponseEntity.notFound().build();
}
}
return ResponseEntity.ok(storyOptional.get());
}
}
所以问题是,我如何实现TODO的