Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: MySQL Replication 수행 #420

Merged
merged 5 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.depromeet.config;

import com.zaxxer.hikari.HikariDataSource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
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;

@Configuration
@Profile("prod")
public class DataSourceConfig {
private static final String PRIMARY_SOURCE = "primaryDataSource";
private static final String SECONDARY_SOURCE = "secondaryDataSource";

@Bean(PRIMARY_SOURCE)
@ConfigurationProperties(prefix = "spring.datasource.primary.hikari")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}

@Bean(SECONDARY_SOURCE)
@ConfigurationProperties(prefix = "spring.datasource.secondary.hikari")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}

@Bean
public DataSource routingDataSource(
@Qualifier(PRIMARY_SOURCE) DataSource primaryDataSource,
@Qualifier(SECONDARY_SOURCE) DataSource secondaryDataSource) {
RoutingDataSource routingDataSource = new RoutingDataSource();

Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put("primary", primaryDataSource);
dataSourceMap.put("secondary", secondaryDataSource);

Map<Object, Object> immutableDataSourceMap = Collections.unmodifiableMap(dataSourceMap);

routingDataSource.setTargetDataSources(immutableDataSourceMap);
routingDataSource.setDefaultTargetDataSource(primaryDataSource);

return routingDataSource;
}

@Bean
@Primary
public DataSource dataSource(@Qualifier("routingDataSource") DataSource routingDataSource) {
return new LazyConnectionDataSourceProxy(routingDataSource);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.depromeet.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing
public class JpaAuditingConfig {}
Original file line number Diff line number Diff line change
@@ -1,8 +1,64 @@
package com.depromeet.config;

import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.context.annotation.Profile;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableJpaAuditing
public class JpaConfig {}
@EnableTransactionManagement
@Profile("prod")
public class JpaConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
penrose15 marked this conversation as resolved.
Show resolved Hide resolved
@Qualifier("dataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactory =
new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource);
entityManagerFactory.setPackagesToScan("com.depromeet");
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setPersistenceUnitName("entityManager");
entityManagerFactory.setJpaProperties(hibernateProperties());

return entityManagerFactory;
}

private JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();

hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
hibernateJpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
return hibernateJpaVendorAdapter;
}

private Properties hibernateProperties() {
Properties properties = new Properties();

properties.setProperty("hibernate.hbm2ddl.auto", "none");
properties.setProperty("hibernate.format_sql", "false");
properties.setProperty(
"hibernate.physical_naming_strategy",
"org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy");

return properties;
}

@Bean
public PlatformTransactionManager transactionManager(
@Qualifier("entityManagerFactory")
LocalContainerEntityManagerFactoryBean entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory.getObject());
return jpaTransactionManager;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.depromeet.config;

import static org.springframework.transaction.support.TransactionSynchronizationManager.*;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class RoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return isCurrentTransactionReadOnly() ? "secondary" : "primary";
}
}
27 changes: 27 additions & 0 deletions module-presentation/src/main/resources/application-prod-db.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
spring:
config:
activate:
on-profile: prod-db
datasource:
primary:
hikari:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: ${PRIMARY_MYSQL_URL}
username: ${PRIMARY_MYSQL_USERNAME}
password: ${PRIMARY_MYSQL_PASSWORD}

secondary:
hikari:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: ${SECONDARY_MYSQL_URL}
username: ${SECONDARY_MYSQL_USERNAME}
password: ${SECONDARY_MYSQL_PASSWORD}
data:
redis:
host: ${REDIS_HOST}
port: ${REDIS_PORT}
password: ${REDIS_PW}

logging:
level:
org.springframework.orm.jpa: INFO
2 changes: 1 addition & 1 deletion module-presentation/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ spring:
active: local # default
group:
local: db, security, actuator, spreadsheet
prod: db, security, actuator, spreadsheet
prod: prod-db, security, actuator, spreadsheet
Loading