multi-datasource 지원 추가
parent
036ffbb552
commit
39f6e58284
@ -0,0 +1,124 @@
|
||||
package cokr.xit.foundation.boot;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
|
||||
import org.egovframe.rte.psl.dataaccess.mapper.MapperConfigurer;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
|
||||
import cokr.xit.foundation.AbstractComponent;
|
||||
import cokr.xit.foundation.Assert;
|
||||
import cokr.xit.foundation.data.paging.MapperSupport;
|
||||
|
||||
/**데이터베이스 접속 관련 설정
|
||||
* <ul><li>{@link #dataSource() 데이터소스} 설정</li>
|
||||
* <li>{@link #sqlSession() MyBatis} 접속 설정</li>
|
||||
* <li>{@link #mapperConfigurer() 매퍼} 설정</li>
|
||||
* </ul>
|
||||
* @author mjkhan
|
||||
*/
|
||||
public abstract class AbstractDatasource extends AbstractComponent {
|
||||
private DataSource dataSource;
|
||||
|
||||
/**데이터소스 Bean을 반환한다. JDBC 접속은 application.yml 파일에 다음과 같이 설정한다.
|
||||
* <pre><code> spring:
|
||||
* datasource:
|
||||
* hikari:
|
||||
* driver-class-name: JDBC 드라이버 클래스 이름
|
||||
* jdbc-url: 데이터베이스 접속 URL
|
||||
* username: 데이터베이스 접속 아이디
|
||||
* password: 데이터베이스 접속 비밀번호</code></pre>
|
||||
* @return 데이터소스
|
||||
*/
|
||||
protected DataSource dataSource() {
|
||||
return dataSource != null ? dataSource : (dataSource = DataSourceBuilder.create().build());
|
||||
}
|
||||
|
||||
/**SqlSessionFactoryBean을 반환한다.<br />
|
||||
* MyBatis의 설정 파일들은 다음 경로에 있어야 한다.
|
||||
* <ul><li>MyBatis 설정: classpath:sql/mybatis-config.xml</li>
|
||||
* <li>매퍼 xml: classpath:sql/mapper/**/*.xml</li>
|
||||
* </ul>
|
||||
* @return SqlSessionFactoryBean
|
||||
*/
|
||||
protected SqlSessionFactoryBean sqlSession() {
|
||||
try {
|
||||
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
|
||||
bean.setDataSource(dataSource());
|
||||
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
bean.setConfigLocation(resolver.getResource("classpath:sql/mybatis-config.xml"));
|
||||
|
||||
Resource[] mapperLocations = getMapperLocations(resolver);
|
||||
if (!isEmpty(mapperLocations))
|
||||
bean.setMapperLocations(mapperLocations);
|
||||
bean.setPlugins(new MapperSupport());
|
||||
bean.setDatabaseIdProvider(databaseIdProvider());
|
||||
return bean;
|
||||
} catch (Exception e) {
|
||||
throw Assert.runtimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**매퍼 위치목록을 반환한다.
|
||||
* @param resolver PathMatchingResourcePatternResolver
|
||||
* @return 매퍼 위치목록
|
||||
* @throws Exception
|
||||
*/
|
||||
private Resource[] getMapperLocations(PathMatchingResourcePatternResolver resolver) throws Exception {
|
||||
List<Resource> resources = Stream.of(mapperLocationPatterns())
|
||||
.flatMap(location -> {
|
||||
try {
|
||||
return Stream.of(resolver.getResources(location));
|
||||
} catch (Exception e) {
|
||||
throw runtimeException(e);
|
||||
}
|
||||
})
|
||||
.toList();
|
||||
return resources.toArray(new Resource[resources.size()]);
|
||||
}
|
||||
|
||||
/**매퍼 경로패턴을 반환한다.
|
||||
* @return 매퍼 경로패턴 목록
|
||||
*/
|
||||
protected String[] mapperLocationPatterns() {
|
||||
return new String[] {"classpath:sql/mapper/**/*.xml"};
|
||||
}
|
||||
|
||||
/**MapperConfigurer를 반환한다.<br />
|
||||
* base package는 cokr.xit로 설정한다.
|
||||
* @return MapperConfigurer
|
||||
*/
|
||||
protected MapperConfigurer mapperConfigurer() {
|
||||
MapperConfigurer bean = new MapperConfigurer();
|
||||
String basePackages = mapperBasePackages();
|
||||
if (!isEmpty(basePackages))
|
||||
bean.setBasePackage(basePackages);
|
||||
bean.setSqlSessionFactoryBeanName(sqlSessionName());
|
||||
return bean;
|
||||
}
|
||||
|
||||
protected String mapperBasePackages() {
|
||||
return "cokr.xit";
|
||||
}
|
||||
|
||||
protected String sqlSessionName() {
|
||||
return "sqlSession";
|
||||
}
|
||||
|
||||
protected VendorDatabaseIdProvider databaseIdProvider() {
|
||||
VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
|
||||
Properties properties = new Properties();
|
||||
properties.put("MariaDB", "mariadb");
|
||||
properties.put("Oracle", "oracle");
|
||||
databaseIdProvider.setProperties(properties);
|
||||
return databaseIdProvider;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package cokr.xit.foundation.boot;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
|
||||
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
|
||||
/**트랜잭션 설정 클래스.
|
||||
* <p>트랜잭션의 적용 대상은 cokr.xit..service.bean..*ServiceBean 클래스의 메소드들이다.
|
||||
* @author mjkhan
|
||||
*/
|
||||
public class AbstractTransaction {
|
||||
private DataSource dataSource;
|
||||
|
||||
public DataSource getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
protected void setDataSource(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
protected DataSourceTransactionManager txManager() {
|
||||
DataSourceTransactionManager bean = new DataSourceTransactionManager();
|
||||
bean.setDataSource(getDataSource());
|
||||
return bean;
|
||||
}
|
||||
|
||||
protected TransactionInterceptor txAdvice() {
|
||||
RuleBasedTransactionAttribute read = new RuleBasedTransactionAttribute(
|
||||
TransactionDefinition.PROPAGATION_REQUIRED,
|
||||
List.of(new RollbackRuleAttribute(Throwable.class))
|
||||
);
|
||||
read.setReadOnly(true);
|
||||
RuleBasedTransactionAttribute write = new RuleBasedTransactionAttribute(
|
||||
TransactionDefinition.PROPAGATION_REQUIRED,
|
||||
List.of(new RollbackRuleAttribute(Throwable.class))
|
||||
);
|
||||
|
||||
NameMatchTransactionAttributeSource txAttrSrc = new NameMatchTransactionAttributeSource();
|
||||
txAttrSrc.setNameMap(Map.of(
|
||||
"get*", read,
|
||||
"*", write
|
||||
));
|
||||
|
||||
TransactionInterceptor bean = new TransactionInterceptor();
|
||||
bean.setTransactionManager(txManager());
|
||||
bean.setTransactionAttributeSource(txAttrSrc);
|
||||
return bean;
|
||||
}
|
||||
|
||||
protected Advisor txAdvisor() {
|
||||
String expression = Foundation.transactionPointcut();
|
||||
AspectJExpressionPointcut requiredTx = new AspectJExpressionPointcut();
|
||||
requiredTx.setExpression(expression);
|
||||
|
||||
DefaultPointcutAdvisor bean = new DefaultPointcutAdvisor();
|
||||
bean.setPointcut(requiredTx);
|
||||
bean.setAdvice(txAdvice());
|
||||
|
||||
return bean;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue