Coupon 미션 중 Read, Write DB가 분리된 분산 데이터베이스 환경에서 DataSource를 연결을 했어야 했다.
그 과정에서 DataSource 빈 주입을 할 때, LazyConnectionDataSourceProxy라는 객체에 대해 알게 되었는데 해당 객체가 무엇이고, 왜 프록시 객체를 빈 등록해주어야 하는지 알아보고자 글을 작성하게 되었다.
@Primary
@DependsOn({"routingDataSource"})
@Bean
public DataSource dataSource(DataSource routingDataSource) {
return new LazyConnectionDataSourceProxy(routingDataSource);
}
LazyConnectionDataSourceProxy란
이름에서 알 수 있듯이, LazyConnectionDataSourceProxy란 데이터 소스에 대한 프록시 객체로, 첫번째 Statement을 생성하기 전까지 실제 JDBC Connections을 느리게 가져오는 객체이다.
느리게 가져오더라도 auto-commit 모드, 트랜잭션 격리 및 read-only 모드와 같은 Connection 초기화 속성은 유지되며 실제 연결이 가져오는 즉시 실제 JDBC 연결에 적용된다.
// 예시
@Autowired
private DataSource dataSource;
public void proxyDatasource() {
// 이 시점에서는 실제 DB 연결이 발생하지 않음
Connection conn = dataSource.getConnection();
// 실제 Statement 생성 시점에 DB 연결이 발생
Statement stmt = conn.createStatement();
}
왜 LazyConnectionDataSourceProxy 를 등록해주어야 할까?
이 데이터 소스 프록시를 사용하면 실제로 필요한 경우가 아니면 풀에서 JDBC 연결을 가져오는 것을 피할 수 있다.
즉, 연결을 했는데 실제로 Statement 문을 사용하지 않는 경우에는 비효율적으로 Connection을 차지하고 있게 된다.
하지만 이 프록시 객체를 사용하면 풀에서 연결을 가져오거나 데이터베이스와 통신하지 않고도 JDBC 트랜잭션 제어를 수행할 수 있으며, 이는 JDBC 문을 처음 생성할 때 지연하여 수행하게 된다.
* 데이터베이스와 통신하지 않고도 JDBC 트랜잭션 제어가 가능하다는 것은 기존 DataSource 사용 시 실제 연결을 해서 불필요한 사용을 하던 것을, 경계만 설정하여 필요할 때만 연결이 가능하도록 한다.
예시 코드
코드로 보면 다음과 같다.
일반적인 DataSource 사용 시에는 불필요한 연결이 발생하게 될 수 있다.
@Transactional
public void normalOperation() {
// 1. 트랜잭션 시작 시점에 즉시 DB 연결을 가져옴
// 2. setAutoCommit(false) 호출 - DB 통신 발생
// 3. 실제로 쿼리를 실행하지 않더라도 연결이 이미 생성됨
if(someCondition) {
// 쿼리 실행하지 않고 리턴하는 경우에도
// 불필요한 DB 연결이 발생했음
return;
}
// 실제 쿼리 실행
}
반면 LazyConnectionDataSourceProxy를 설정하게 되면 같은 상황에서 ProxyConnection을 가지고 있게 된다.
@Transactional
public void lazyOperation() {
// 1. 트랜잭션 시작 시점에 실제 DB 연결을 가져오지 않음
// 2. 트랜잭션 경계만 설정됨
if(someCondition) {
// 쿼리를 실행하지 않고 리턴하는 경우
// DB 연결 자체가 생성되지 않음 -> 리소스 절약
return;
}
// 실제 쿼리 실행 시점에 처음으로 DB 연결 생성
repository.findById(id); // 여기서 첫 DB 연결 발생
}
즉, LazyConnectionDataSourceProxy를 사용하면 트랜잭션 관리는 하되, 실제 DB 연결은 필요한 시점까지 지연시킬 수 있어 리소스를 효율적으로 사용할 수 있게 되는 것이다.
'Spring 🟢' 카테고리의 다른 글
[Spring] 시큐리티로 JWT 로그인 구현하기 (0) | 2023.10.20 |
---|---|
[JPA] 기본키 매핑(IDENTITY, SEQUENCE 전략) (0) | 2023.08.11 |
filter와 Interceptor (0) | 2023.08.04 |
[Spring] RowMapper (2) | 2023.06.09 |
[Intellij] Cause: error: invalid source release: 16 해결하기 (0) | 2023.06.02 |