基于与AbstractRoutingDataSource的先前查找动态地使用其他数据库

时间:2019-06-19 14:48:50

标签: java spring spring-boot spring-data-jpa

我们的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的

0 个答案:

没有答案