프록시 JDBC(1)
- 개발
- 2026. 3. 8. 22:52
이전에 저는 파일을 통해 slow쿼리를 계산을 진행하였습니다. 하지만 그러다 보니 실시간으로 메시지를 보여주지 못하였습니다. 처음 의도가 네트워크 상황이라던지 여러 요인들이 존재하기 때문에 파일을 읽는 것을 선택하였지만, 곰곰히 생각해보니 그것을 어플리케이션 쪽에서 파일을 읽을 필요는 없었습니다. 어플리케이션에서 slow쿼리를 확인할때 그것이 네트워크 이슈나 다른 이슈들이 섞여있지 않다는 것을 확인할 필요가 없었습니다. 만약, db쪽에 slow쿼리 이슈라면 파일만 만들어두고 확인하는 방법을 선택하면 되었기 때문입니다. 그래서 slow쿼리를 파일로 읽는 방식이 아닌 datasource를 이용해서 어플리케이션에서 읽는 방법을 선택하였습니다. 중요한 사실은 datasorce에서시간 측정하는 것은 불가능합니다. 이것을 가능하게 하는것이 프록시입니다. 이 파트에서 설명할 주제는 프록시 jdbc입니다.
프록시 JDBC는 무엇일까?
프록시 JDBC를 알기전에 프록시가 무엇인지 부터 알아보는게 좋을거 같습니다.
프록시는 대리인이라는 뜻을 가지고 있습니다. 즉, 프록시 JDBC는 JDBC를 대신해서 무언가를 처리를 해주는 것을 의미합니다.
그렇다면 프록시 JDBC는 어떻게 하면 만들 수 있을까요?
이제 Java 애플리케이션이 JDBC를 통해 데이터베이스에 어떻게 접근하는지 살펴보겠습니다. Java에서는 데이터베이스와 직접 연결하기 위해 JDBC(Java Database Connectivity) 를 사용합니다. 일반적으로 애플리케이션은 JDBC를 사용할 때 DataSource를 통해 Connection을 획득하게 됩니다. DataSource는 데이터베이스 연결 정보를 관리하고, 애플리케이션이 데이터베이스와 연결할 수 있도록 Connection을 제공하는 객체입니다.
즉, Java 애플리케이션에서 데이터베이스에 접근하는 흐름은 다음과 같습니다.
DataSource → Connection → PreparedStatement → execute
JDBC를 대신해서 시간을 측정을 하는 것을 만들 기 위해서는 execute쪽에 프록시 객체를 만들면 되지 않을까요?
이러한 방식이라면 Service나 Repository 메서드 전체 시간이 아니라, 실제로 실행된 SQL 단위로 정확한 실행 시간을 측정할 수 있습니다.
하지만 execute만 프록시 객체로 만들어서 사용하기는 어렵다고 합니다. 그 이유가 무엇일까요?
execute만 프록시 객체로 만들어서 사용하기는 어려운 이유?
핵심은 생성 지점입니다. PreparedStatement는 Connection.prepareStatement()를 통해 생성되어 즉시 호출자에게 반환됩니다. 따라서 이 반환 과정에 개입하지 못하면 원본 객체를 프록시 객체로 치환할 수 없습니다. 결국 자동 적용을 위해서는 Connection이나 DataSource를 래핑하거나, 더 아래 계층인 JDBC 드라이버 수준에서 개입해야 합니다.
결국은 execute를 실행하기 위해서는 PreparedStatement가 필요하고,
PreparedStatement를 생성하기 위해서는 Connection을 필요하고,
Connection은 DataSource를 통해 생성되어집니다. 결국 DataSource부터 Wrapper 객체로 만들어야 합니다.
결국 객체 생성 흐름의 시작점인 DataSource 단계부터 프록시를 적용해야 합니다.
다행스럽게도 스프링은 DataSource를 Wrapper 객체를 제공해주고 있네요. 바로 DelegatingDataSource입니다.
그렇다면 DelegatingDataSource가 어떤것인지 알아봅시다.
DelegatingDataSource는 무엇인가?
DelegatingDataSource는 Spring에서 제공하는 DataSource Wrapper 클래스입니다.
이 클래스의 역할은 기존 DataSource를 감싸서 호출을 위임(delegate)하면서 필요한 동작을 확장할 수 있도록 하는 것입니다.
즉, DelegatingDataSource 자체가 특별한 로직을 수행하는 것은 아니고, 기존 DataSource를 감싸는 기본 구조를 제공하는 클래스라고 볼 수 있습니다.
그렇다면 DelegatingDataSource로 무엇을 할 수 있을까?
즉, DataSource를 그대로 두면서, 중간에 원하는 동작을 추가할 수 있게 해줍니다.
예를 들어 getConnection()이 호출될 때 로그를 남기는 작업, 반환되는 Connection을 감싸는 작업,추가 설정을 넣는 작업
같은 작업들을 할 수 있습니다. 쉽게 말해서, 기존 DataSource를 바꾸지 않고 확장할 수 있게 해주는 Wrapper라고 보면 됩니다.
우리가 짚고 넘어가야 할 부분이 있습니다. 바로 반환되는 Connection을 감싸는 작업과 추가 설정을 넣는 작업입니다.
얘네가 왜 중요하냐면
DataSource → Connection → PreparedStatement → execute
이 흐름에서 다음 단계로 가기 위해서는 Connection을 감싸야 하기 때문이죠.
결론
주말이라 생각보다 많이 쓰지 못하였습니다. 최대한 이것을 왜 사용하고 좀더 줄일 수 없을까 라는 고민을 했던거 같습니다.
오늘은 조금 더 쉬고 싶어서 내일로 미루려고 합니다.
다음 글에서는 프록시 객체로 만들 수 있는지 확인해봅시다.
'개발' 카테고리의 다른 글
| OpenAI는 어떻게 PostgreSQL을 스케일했을까 (0) | 2026.03.10 |
|---|---|
| 프록시 JDBC(2) (0) | 2026.03.09 |
| 분명... slow쿼리를 모니터링하려고 했는데... 어째서... (0) | 2026.03.06 |
| 데이터베이스의 종류 (0) | 2026.03.05 |
| kafka가 Zookeeper대신 KRaft를 사용하는 이유가 뭘까? (1) | 2026.03.04 |