package kr.wisestone.owl.config; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import kr.wisestone.owl.config.persistence.aop.TransactionDefinitionInterceptor; import kr.wisestone.owl.config.persistence.routing.TransactionDefinitionRoutingDataSource; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.SqlSessionFactory; import org.flywaydb.core.Flyway; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.TransactionManagementConfigurer; import org.springframework.transaction.interceptor.TransactionAttributeSource; import javax.persistence.SharedCacheMode; import javax.persistence.ValidationMode; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * Created by jeong on 2017-08-02. */ @Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = {"kr.wisestone.owl.repository"}, entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "jpaTransactionManager" ) @EnableAspectJAutoProxy public class DataBaseConfiguration implements TransactionManagementConfigurer { @Value("${db.primary.driverName}") private String dbPrimaryDriverName; @Value("${db.primary.url}") private String dbPrimaryUrl; @Value("${db.primary.userName}") private String dbPrimaryUserName; @Value("${db.primary.password}") private String dbPrimaryPassword; @Value("${db.replica1.url}") private String dbReplica1PrimaryUrl; @Value("${db.replica2.url}") private String dbReplica2PrimaryUrl; @Value("${db.replica3.url}") private String dbReplica3PrimaryUrl; @Value("${db.replica4.url}") private String dbReplica4PrimaryUrl; @Value("${db.replica5.url}") private String dbReplica5PrimaryUrl; @Bean public TransactionDefinitionInterceptor transactionDefinitionInterceptor(TransactionAttributeSource transactionAttributeSource) { return new TransactionDefinitionInterceptor(transactionAttributeSource); } @Bean public DataSource dataSource() { final TransactionDefinitionRoutingDataSource transactionDefinitionRoutingDataSource = new TransactionDefinitionRoutingDataSource(); final Map targetDataSources = new HashMap<>(); this.setReplica(targetDataSources, this.dbReplica1PrimaryUrl, 1); this.setReplica(targetDataSources, this.dbReplica2PrimaryUrl, 2); this.setReplica(targetDataSources, this.dbReplica3PrimaryUrl, 3); this.setReplica(targetDataSources, this.dbReplica4PrimaryUrl, 4); this.setReplica(targetDataSources, this.dbReplica5PrimaryUrl, 5); transactionDefinitionRoutingDataSource.setDefaultTargetDataSource(this.buildDataSource("primaryHikariPool", this.dbPrimaryUrl, this.dbPrimaryUserName, this.dbPrimaryPassword, this.dbPrimaryDriverName)); // master db transactionDefinitionRoutingDataSource.setTargetDataSources(targetDataSources); return transactionDefinitionRoutingDataSource; } // 리플리카 설정 private void setReplica(Map targetDataSources, String replicaUrl, int count) { if (!StringUtils.isEmpty(replicaUrl)) { targetDataSources.put("replica" + count, this.buildDataSource("replicaHikariPool" + count, replicaUrl, this.dbPrimaryUserName, this.dbPrimaryPassword, this.dbPrimaryDriverName)); } } private DataSource buildDataSource(String poolName, String jdbcUrl, String userName, String password, String driverClassName) { HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setMinimumIdle(40); hikariConfig.setConnectionTimeout(10000); hikariConfig.setMaxLifetime(58000); hikariConfig.setValidationTimeout(10000); hikariConfig.setMaximumPoolSize(40); hikariConfig.setConnectionTestQuery("SELECT 1"); hikariConfig.setPoolName(poolName); hikariConfig.setJdbcUrl(jdbcUrl); hikariConfig.setUsername(userName); hikariConfig.setPassword(password); hikariConfig.setDriverClassName(driverClassName); return new HikariDataSource(hikariConfig); } @Override public PlatformTransactionManager annotationDrivenTransactionManager() { return this.jpaTransactionManager(); } @Bean public PlatformTransactionManager jpaTransactionManager() { JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); jpaTransactionManager.setEntityManagerFactory(this.entityManagerFactory().getObject()); return jpaTransactionManager; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect"); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(adapter); factory.setDataSource(this.dataSource()); factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE); factory.setValidationMode(ValidationMode.NONE); factory.setPackagesToScan("kr.wisestone.owl.domain"); factory.setMappingResources("META-INF/orm.xml"); factory.setJpaPropertyMap(this.getJpaProperties()); return factory; } private Map getJpaProperties() { Map jpaProperties = new HashMap<>(); jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect"); jpaProperties.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver"); jpaProperties.put("hibernate.physical_naming_strategy", "kr.wisestone.owl.domain.strategy.PrefixNamingStrategy"); jpaProperties.put("hibernate.show_sql", "false"); jpaProperties.put("hibernate.format_sql", "true"); jpaProperties.put("hibernate.use_sql_comments", "true"); jpaProperties.put("hibernate.session_factory.interceptor", "kr.wisestone.owl.domain.interceptor.AuditLogInterceptor"); return jpaProperties; } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); sqlSessionFactoryBean.setConfigLocation( new PathMatchingResourcePatternResolver().getResource("classpath:/mybatis/config/mybatis-config.xml") ); sqlSessionFactoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath:/mybatis/query-template*//*.xml") ); return sqlSessionFactoryBean.getObject(); } @Bean(initMethod = "migrate") public Flyway flyway(DataSource dataSource) { Flyway flyway = new Flyway(); flyway.setBaselineOnMigrate(true); flyway.setLocations("classpath:/migration"); flyway.setDataSource(dataSource); return flyway; } }