일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- gRPC
- next-stock
- ipo 매매자동화
- 셀러리
- 디버깅
- AWS
- BFS
- 몽고 인덱스
- 카카오
- 베타적락
- 추천 검색 기능
- 알람시스템
- 백준
- 쿠키
- piplining
- 구현
- ai agent
- 완전탐색
- spring event
- 아키텍쳐 개선
- docker
- 프로그래머스
- 관측가능성
- 결제서비스
- 이분탐색
- 크롤링
- JPA
- 누적합
- langgraph
- dau 3만명
- Today
- Total
코딩관계론
인터페이스를 통해 DB를 표준화했다고?(JDBC) 본문
JDBC(Java Database Connectivity)는 자바를 통해 데이터베이스에 접근할 수 있도록 해주는 API입니다. 이 API는 자바 응용 프로그램과 데이터베이스 사이의 연결을 관리하고 쿼리를 실행하며 결과를 처리할 수 있도록 표준 인터페이스를 제공합니다
왜 JDBC 표준 API가 필요했을까?
JDBC 표준 API가 필요했던 이유는 벤더사마다 기능 구현이 달라질 경우, 데이터베이스를 변경할 때마다 코드 수정을 해야 하는 번거로움을 방지하기 위해서입니다. JDBC는 다양한 데이터베이스 벤더의 드라이버를 추상화하여 일관된 방식으로 데이터베이스에 접근할 수 있게 해줍니다. 이를 위해 자바 진영에서는 Driver 인터페이스를 제공하고, 각 벤더사에서 해당 Driver를 구현하여 라이브러리로 배포하게 됩니다.
Driver를 불러오는 방식
Driver를 관리하는 것이 DriverManager입니다. 클래스 로더가 각 벤더사가 구현한 Driver 클래스를 로드하게 되고, DriverManager가 각 벤더사의 connect 함수를 통해 데이터베이스에 접속을 시도합니다. 연결이 성공하면 Connection 객체를 반환하게 됩니다.
아래는 java.sql 패키지의 getConnection 함수입니다. 코드를 보면 클래스 로더로부터 정보를 얻어와 for문을 통해 각 드라이버가 구현한 connect 함수를 호출하는 것을 볼 수 있습니다. 항상 Connection 객체를 반환하는데, null이 아니면 연결에 성공한 것임으로 Connection 객체를 반환합니다.
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
if (callerCL == null || callerCL == ClassLoader.getPlatformClassLoader()) {
callerCL = Thread.currentThread().getContextClassLoader();
}
if (url == null) {
throw new SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
ensureDriversInitialized();
// Walk through the loaded registeredDrivers attempting to make a connection.
// Remember the first exception that gets raised so we can reraise it.
SQLException reason = null;
for (DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if (isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.driver.getClass().getName());
}
}
// if we got here nobody could connect.
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
throw new SQLException("No suitable driver found for "+ url, "08001");
}
}
그럼 쿼리의 표준화는?
데이터베이스에 접속하는 방법은 표준화되었지만, 쿼리를 실행하는 방법도 표준화되어야 합니다. 각 벤더마다 쿼리를 날리는 방식이 다를 수 있기 때문에 자바 진영에서는 Statement와 PreparedStatement 인터페이스를 이용하여 이를 표준화했습니다. PreparedStatement는 쿼리 파라미터를 설정하여 DB로 쿼리를 날릴 수 있는 점에서 Statement와 차이가 있습니다.
쿼리 객체는 어떻게 얻어올까?
쿼리 객체는 다음과 같은 방식으로 얻어옵니다:
- Connection 객체로 createStatement나 prepareStatement를 호출합니다.
- 벤더사에서 Statement 또는 PreparedStatement 인터페이스를 구현한 객체를 반환합니다.
아래 코드는 Connection 객체를 얻어와 prepareStatement를 호출하고, 쿼리를 실행하는 예제입니다.
public void save(Member member) {
String sql = "INSERT INTO member(member_id, money) values (?, ?)";
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, member.getMemberId());
preparedStatement.setInt(2, member.getMoney());
preparedStatement.execute();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
close(connection, preparedStatement, null);
}
}
그럼 결과는 어떤 인터페이스로 받을까?
자 이정도 됐으면 DB에 의존하는 모든 것은 Interface로 느슨하게 결합됐다는 것을 인지했을 것이다. 그럼 조회 결과는 어떤 인터페이스로 받을까? 바로 ResultSet으로 받게 된다.
ResultSet은 JDBC에서 쿼리 결과를 저장하고 탐색하는 데 사용되는 인터페이스입니다. 쿼리 실행 후 반환된 ResultSet 객체는 데이터베이스로부터 읽어온 데이터를 행(row) 단위로 접근할 수 있도록 합니다.
아래 코드는 원하는 멤버를 찾고 해당 결과를 조회하는 코드를 나타낸다. 특이한 점은 next()를 먼저 호출해줘야 하는 점인데 그 이유는 ResultSet 객체는 초기 생성 시 커서가 첫 번째 행의 앞에 위치합니다. 따라서 데이터를 읽으려면 next() 메서드를 호출하여 커서를 첫 번째 행으로 이동해야 합니다.
public Member findById(String memberId, Connection connection) {
String sql = "SELECT * FROM member WHERE member_id = ?";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, memberId);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
Member member = new Member();
member.setMemberId(resultSet.getString("member_id"));
member.setMoney(resultSet.getInt("money"));
return member;
} else {
throw new NoSuchElementException("member id cant find" + memberId);
}
} catch (SQLException e) {
log.error(e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
그럼 최종 도식도는 다음과 같이 되며, 이 그림의 출처는 아래의 링크에 달아두겠다.
결론
JDBC(Java Database Connectivity)는 자바 애플리케이션이 다양한 데이터베이스와 상호작용할 수 있도록 해주는 중요한 API입니다. JDBC의 표준 API를 사용하면 데이터베이스 벤더마다 다른 구현 방식을 추상화하여, 코드 변경 없이 데이터베이스를 교체할 수 있는 유연성을 제공합니다. 이를 통해 개발자는 데이터베이스 관련 코드를 쉽게 작성하고 유지보수할 수 있습니다.
[참고자료]
1. https://www.geeksforgeeks.org/establishing-jdbc-connection-in-java/
Establishing JDBC Connection in Java - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.
www.geeksforgeeks.org
깊게 생각해보기
ORM이 뭘까?
ORM은 결국 JDBC 인터페이스를 구현한 것이며 사용자에게 편의성을 제공하기 위함이다.
'개발 > Java' 카테고리의 다른 글
클러스터링과 논클러스트링이란? (0) | 2024.07.03 |
---|---|
DB Connection Pool은 왜 필요할까? (0) | 2024.07.02 |
JSP 어떻게 Servlet으로 변환되서 Client에게 전달되는가 (0) | 2024.06.27 |
자바의 HashMap은 어떻게 구현되어 있나? (0) | 2024.06.20 |
Synchronized Collection VS Concurrent Collection (0) | 2024.06.19 |