diff --git a/backend/baton/secret b/backend/baton/secret index c80dbdac1..b608f4686 160000 --- a/backend/baton/secret +++ b/backend/baton/secret @@ -1 +1 @@ -Subproject commit c80dbdac1aee84ada6e6b63bdce49173579a5f73 +Subproject commit b608f46867c509c7efb5018335b733c86b3a59a7 diff --git a/backend/baton/src/main/java/touch/baton/config/DataSourceConfig.java b/backend/baton/src/main/java/touch/baton/config/DataSourceConfig.java new file mode 100644 index 000000000..56da8ba38 --- /dev/null +++ b/backend/baton/src/main/java/touch/baton/config/DataSourceConfig.java @@ -0,0 +1,55 @@ +package touch.baton.config; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; +import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy; +import touch.baton.infra.database.datasource.DataSourceType; +import touch.baton.infra.database.datasource.RoutingDataSource; + +import javax.sql.DataSource; +import java.util.Map; + +import static touch.baton.infra.database.datasource.DataSourceType.Name.REPLICA_NAME; +import static touch.baton.infra.database.datasource.DataSourceType.Name.ROUTING_NAME; +import static touch.baton.infra.database.datasource.DataSourceType.Name.SOURCE_NAME; + +@Profile("deploy") +@Configuration +public class DataSourceConfig { + + @Qualifier(SOURCE_NAME) + @ConfigurationProperties(prefix = "spring.datasource.source") + @Bean + public DataSource sourceDataSource() { + return DataSourceBuilder.create().build(); + } + + @Qualifier(REPLICA_NAME) + @ConfigurationProperties(prefix = "spring.datasource.replica") + @Bean + public DataSource replicaDataSource() { + return DataSourceBuilder.create().build(); + } + + @Qualifier(ROUTING_NAME) + @Bean + public DataSource routingDataSource(@Qualifier(SOURCE_NAME) final DataSource sourceDataSource, + @Qualifier(REPLICA_NAME) final DataSource replicaDataSource + ) { + return RoutingDataSource.createDefaultSetting( + Map.of(DataSourceType.SOURCE, sourceDataSource, + DataSourceType.REPLICA, replicaDataSource) + ); + } + + @Bean + @Primary + public DataSource dataSource(@Qualifier(ROUTING_NAME) final DataSource replicationRoutingDataSource) { + return new LazyConnectionDataSourceProxy(replicationRoutingDataSource); + } +} diff --git a/backend/baton/src/main/java/touch/baton/infra/database/datasource/DataSourceType.java b/backend/baton/src/main/java/touch/baton/infra/database/datasource/DataSourceType.java new file mode 100644 index 000000000..c441fafd5 --- /dev/null +++ b/backend/baton/src/main/java/touch/baton/infra/database/datasource/DataSourceType.java @@ -0,0 +1,24 @@ +package touch.baton.infra.database.datasource; + +import static touch.baton.infra.database.datasource.DataSourceType.Name.REPLICA_NAME; +import static touch.baton.infra.database.datasource.DataSourceType.Name.SOURCE_NAME; + +public enum DataSourceType { + + SOURCE(SOURCE_NAME), + REPLICA(REPLICA_NAME); + + private final String name; + + DataSourceType(final String name) { + this.name = name; + } + + public static class Name { + + public static final String ROUTING_NAME = "ROUTING"; + public static final String SOURCE_NAME = "SOURCE"; + public static final String REPLICA_NAME = "REPLICA"; + } + +} diff --git a/backend/baton/src/main/java/touch/baton/infra/database/datasource/RoutingDataSource.java b/backend/baton/src/main/java/touch/baton/infra/database/datasource/RoutingDataSource.java new file mode 100644 index 000000000..fda80330e --- /dev/null +++ b/backend/baton/src/main/java/touch/baton/infra/database/datasource/RoutingDataSource.java @@ -0,0 +1,27 @@ +package touch.baton.infra.database.datasource; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import java.util.Map; + +public class RoutingDataSource extends AbstractRoutingDataSource { + + public static RoutingDataSource createDefaultSetting(final Map dataSources) { + final RoutingDataSource routingDataSource = new RoutingDataSource(); + routingDataSource.setDefaultTargetDataSource(dataSources.get(DataSourceType.SOURCE)); + routingDataSource.setTargetDataSources(dataSources); + return routingDataSource; + } + + @Override + protected Object determineCurrentLookupKey() { + final boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); + + if (readOnly) { + return DataSourceType.REPLICA; + } + + return DataSourceType.SOURCE; + } +}