Динамически использовать другую базу данных на основе предыдущего поиска с AbstractRoutingDataSource - PullRequest
0 голосов
/ 19 июня 2019

Мы столкнемся с большим объемом данных в наших базах данных mariadb.Чтобы преодолеть проблемы с резервным копированием и операциями ddl, у нас была идея хранить данные в нескольких базах данных.В основном у нас будет база данных с краткосрочными данными (например, за последние 30 дней, с именем short_term) и еще одна с остальными данными (с именем long_term).Очевидно, что данные должны быть перемещены из short_term в long_term, но это должно быть достижимо.

Проблема, с которой я сталкиваюсь в настоящее время на прототипе, заключается в том, что я могу подключиться к short_term, но не могу переключиться на long_term, если дляПример хочу запросить их обоих (например, get (), где я не могу найти его в базе данных short_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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...