이전에 블로그에 spring boot 로 여러개의 데이터베이스를 연결하는걸 작성한적이 있다. 어떤 서버든 개인적으로는 하나의 데이터베이스만 접근해서 사용하는게 좋다고 생각하지만 ( MSA 스럽지 못하다! ) 어쩔수 없이 여러 데이터베이스의 정보를 가져와야 하는경우가 생긴다. 가령 이곳저곳 데이터를 수집하는 경우라면....
API 로 제공 받아서 연동하는게 가장 best 한 case 가 되겠지만 지금 상황(?) 상 api 를 제공 받지 못하는 상황이라면 직접 데이터베이스에 접근해야만 하는 상황이 생겼다.
아주 중요한 설정이다. 다른설정을 다해도 이설정이 없다면 제대로 동작이 불가능하다. 간략하게 설명하면 articleDataSource() 에서 datasource 를 생성하고 transactionManager() 에서 그에 맞는 트랙젝션 설정을 한다. 그리고 jooq 을 사용하기 위한 핵심인데 dslContext() 에서 jooq 을 사용하기 위한 설정을 하는것이다. 이 구조에 대해서 개념을 너무 어렵게 생각해서 헤매고있었는데 zepinos 님 덕분에 좀 수월하게 정리가 된거 같다.
원리는 간단하다! 트랜젝션 설정까지는 철저히 spring boot 영역이다. 그리고 그걸 이용하는건 mybatis, jpa, jooq 각자의 설정에 따라 알아서 가져가는걸로 이해하면된다. 그렇기 때문에 dslContext() 이부분을 mybatis 라면 sessionFactory 설정을 해주면 되고 JPA 면 JPAsession 설정으로 교체만 해주면 되는것이다. 참 간단하다!
추가 적으로 jooq 을 사용하게 될경우 jooq 에서 발생하는 Exception 을 catch 하여 처리할 필요가 있다. 그럴때 보통 Exception 처리를 위한 설정을 해주게 되는데 위에 설정에 보면 new JOOQToSpringExceptionTransformer() 이란것을 사용하고 있다. 이부분도 정의 해주도록 하자.
import org.jooq.ExecuteContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DefaultExecuteListener;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
public class JOOQToSpringExceptionTransformer extends DefaultExecuteListener {
@Override
public void exception(ExecuteContext ctx) {
SQLDialect dialect = ctx.configuration().dialect();
SQLExceptionTranslator translator = (dialect != null)
? new SQLErrorCodeSQLExceptionTranslator(dialect.name())
: new SQLStateSQLExceptionTranslator();
ctx.exception(translator.translate("jOOQ", ctx.sql(), ctx.sqlException()));
}
}
이제부터 각 데이터베이스에 대한 각각의 설정을 해주려고 한다. 먼저 yml 설정이 필요하다 각 디비의 접속정보를 세팅해주는데 기존의 jdbc 를 설정하는 방식과는 많이 다르다.
spring:
jta:
enabled: true
original :
datasource:
jdbc-url: jdbc:mysql://xxxxxxxxxxx.com:3306
password: xxxxx
username: xxxxxxx
driverClassName: com.mysql.cj.jdbc.Driver
first :
datasource:
xa-data-source-class-name: com.mysql.cj.jdbc.MysqlXADataSource
xa-properties:
server-name: xxxxxxxxxxxxx.com
database-name: xxxxx
password: xxxxxxx
user: xxxxxx
port-number: 3306
second:
datasource:
xa-data-source-class-name: com.mysql.cj.jdbc.MysqlXADataSource
xa-properties:
server-name: localhost
database-name: test
password: test
user: test
port-number: 3306
jooq:
sql-dialect: mysql
메인 커넥션을 제외하고 XA 를 사용하기 때문에 설정 자체도 XA 기반으로 해주어야 한다. 여기서 중요한건 메인 디비 정보도 xa 로 한번더 설정해준다는것이다. 왜냐하면 하나의 트랜잭션으로 묶어서 사용하기때문인거 같다. 그리고 jta 설정을 true 로 명시하여 spring boot 가 인지하도록 해준다. 각각에 들어가는 값들을 보면 기존과 다른것이 없기 때문에 그게 어려울것이 없다.
설정을 완료 했다. 이제 어떻게 사용하는지도 보려고 한다. 사용법은 아주 단순하다. Repository에서 필요한 디비를 @Qualifier 로 지정해서 주입만 해주면 된다.
아래는 간단하게 spring batch 사용시 사용되는 테이블을 조회하는경우를 샘플로 가져와 보았다.
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.jooq.impl.DSL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Slf4j
@Repository
public class LoginRepository {
@Autowired
@Qualifier("firstDsl")
DSLContext dsl;
public int test() throws Exception{
return dsl.selectCount().from(DSL.table("BATCH_JOB_EXECUTION") ).limit(1).execute();
}
}
jooq 쿼리 자체는 말이 안되지만 쿼리를 보는게 목적이 아니기 때문에 무시하고 넘어간다. 핵심은 @Qualifier("firstDsl") 이다!! 이전 설정에서 bean 이름을 firstDsl 로 정의해놓았다. 그리고 정의된 bean 이름을 dsl 이라는 클래스변수에 주입하여 사용 하면 된다는 것이다. 다른 커넥션을 이용하고자하면 fisrtDsl -> secondDsl 이런식으로 바꿔주면 된다. 필요하다면 둘다 사용해도 무방하다.
두개의 데이터베이스 접근가능한것을 이미 확인했고 쿼리도 정상 동작하는것을 확인했다. 아직 트랜잭션 테스트까진는 확인 하지 못했다. 아마 되지 않을까 싶다. 이전 블로그에서의 데이터베이스 연결을 반쪽 짜리 인거 같다. 트랜잭션에 대한 부분까지는 고려못하고 글을 작성했고 추후에 mybatis를 사용하게된다면 이 글을 참조해서 사용해야 할거 같다.