1. 학습 주제
JDBC의 기본 연결부터 Statement, PreparedStatement, SQL Injection 방어, 그리고 CRUD와 DAO + DTO + XML 쿼리 분리 구조까지 학습했다.
단순히 SQL을 실행하는 수준을 넘어서, 자바 애플리케이션이 데이터베이스와 어떻게 역할을 나눠서 연결되는지 흐름을 익히는 데 집중했다.
- JDBC로 DB 연결하기
- properties 파일로 접속 정보 분리하기
- JDBCTemplate로 공통 코드 정리하기
- Statement와 PreparedStatement 차이 이해하기
- ResultSet으로 조회 결과 읽기
- SQL Injection이 왜 위험한지 확인하기
- CRUD의 기본 흐름 익히기
- DTO, DAO, XML 쿼리 분리 구조 이해하기
2. JDBC란
JDBC는 Java Database Connectivity의 약자로, 자바 프로그램이 데이터베이스와 통신할 수 있게 해주는 API이다.
JDBC의 기본 흐름은 보통 다음과 같다.
- Connection 생성
- SQL 실행 객체 생성
- SQL 실행
- 결과 처리
- 자원 반납
즉 자바 코드 안에서 DB에 접속하고, SQL을 전달하고, 결과를 객체로 받아오는 전체 통로라고 이해하면 된다.
3. DB 연결과 Connection
가장 먼저 필요한 것은 Connection 객체이다.
Class.forName("com.mysql.cj.jdbc.Driver");
con = DriverManager.getConnection(
"jdbc:mysql://localhost/employeedb",
"ohgiraffers",
"ohgiraffers"
);
- JDBC 드라이버를 로딩한다
- DB 주소, 계정, 비밀번호를 전달한다
- 연결이 성공하면 Connection 객체를 얻는다
Connection은 자바와 데이터베이스 사이의 연결 통로 역할을 한다.
4. properties 파일로 설정 분리
접속 정보를 코드에 직접 쓰는 대신 connection-info.properties 파일에서 읽어오는 방식도 학습했다.
Properties prop = new Properties();
prop.load(reader);
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String user = prop.getProperty("user");
String password = prop.getProperty("password");
이 구조의 장점은:
- 접속 정보 수정이 쉬워진다
- 코드와 설정을 분리할 수 있다
- 유지보수성이 좋아진다
실무에서는 이런 방식이 훨씬 일반적이다.
5. JDBCTemplate
JDBC를 쓰다 보면 매번 반복되는 코드가 많다.
- Connection 열기
- Connection 닫기
- Statement 닫기
- ResultSet 닫기
그래서 예제에서는 JDBCTemplate 클래스로 공통 로직을 분리했다.
public static Connection getConnection() { ... }
public static void close(Connection con) { ... }
public static void close(Statement stmt) { ... }
public static void close(ResultSet rset) { ... }
이 방식의 핵심은:
- 중복 제거
- 실수 방지
- 코드 가독성 향상
즉 JDBCTemplate는 JDBC에서 자주 반복되는 연결/닫기 코드를 재사용하기 위한 공통 도구이다.
6. Statement와 SELECT 조회
가장 기본적인 SQL 실행 객체는 Statement이다.
stmt = con.createStatement();
rset = stmt.executeQuery("SELECT MENU_NAME, MENU_PRICE FROM TBL_MENU");
조회 결과는 ResultSet으로 받는다.
while(rset.next()) {
System.out.println(
rset.getString("MENU_NAME") + ", " + rset.getInt("MENU_PRICE")
);
}
여기서 핵심은:
- executeQuery()는 SELECT용
- ResultSet은 조회 결과 집합
- next()는 다음 행으로 이동
- getString(), getInt() 등으로 현재 행 값을 읽는다
7. ResultSet
ResultSet은 데이터베이스에서 조회한 결과를 자바에서 한 줄씩 읽기 위한 객체이다.
흐름은 이렇게 이해하면 쉽다.
- SQL 실행
- 결과가 ResultSet에 담김
- next()로 한 행씩 이동
- 각 컬럼 값을 꺼냄
즉 ResultSet은 “조회된 테이블 결과를 자바 코드에서 순차적으로 읽는 도구”이다.
8. Statement의 한계
Statement로 사용자 입력을 그대로 이어붙여 쿼리를 만들 수도 있다.
String query =
"SELECT MENU_NAME, MENU_PRICE FROM TBL_MENU WHERE MENU_CODE = '" + menuCode + "'";
하지만 이런 방식은 문제가 있다.
- 문자열 연결이 번거롭다
- 타입 처리도 불편하다
- 잘못된 입력이 SQL 구조를 깨뜨릴 수 있다
- SQL Injection에 취약하다
즉 Statement는 단순 실행에는 가능하지만, 사용자 입력이 들어가는 동적 쿼리에는 위험하다.
9. PreparedStatement
PreparedStatement는 SQL 문장을 미리 준비하고, 값은 나중에 안전하게 채워 넣는 방식이다.
String query = "SELECT MENU_NAME FROM TBL_MENU WHERE MENU_CODE = ?";
pstmt = con.prepareStatement(query);
pstmt.setString(1, menuCode);
rset = pstmt.executeQuery();
핵심은 ? 위치 홀더이다.
- SQL 구조는 고정
- 입력값은 데이터로만 들어감
- 문법과 값을 분리할 수 있다
장점:
- SQL Injection 방어
- 가독성 향상
- 값 바인딩이 명확함
- 동적 입력 처리에 적합
실무에서는 Statement보다 PreparedStatement를 훨씬 더 자주 사용한다.
10. SQL Injection
예제에서는 SQL Injection 공격도 확인했다.
private static String empName = "' OR 1=1 AND EMP_ID = '200";
이 값을 Statement 방식으로 이어붙이면 SQL 조건식 자체가 변형될 수 있다.
즉 SQL Injection은:
- 사용자 입력이 단순 값이 아니라
- SQL 문법 일부처럼 해석되면서
- 원래 의도하지 않은 쿼리가 실행되는 문제
이다.
PreparedStatement는 이 입력값을 SQL 구조가 아니라 데이터 값으로만 다루기 때문에 이런 공격을 막는 데 매우 중요하다.
11. DTO 사용
조회 결과를 바로 출력만 하는 것이 아니라, DTO 객체에 담는 방식도 학습했다.
예: MenuDTO
row = new MenuDTO();
row.setMenuCode(rset.getInt("MENU_CODE"));
row.setMenuName(rset.getString("MENU_NAME"));
row.setMenuPrice(rset.getInt("MENU_PRICE"));
row.setCategoryCode(rset.getInt("CATEGORY_CODE"));
row.setOrderableStatus(rset.getString("ORDERABLE_STATUS"));
그리고 여러 행은 List<MenuDTO>에 담았다.
DTO를 쓰는 이유:
- 한 행의 데이터를 객체로 표현할 수 있다
- 출력, 전달, 재사용이 쉬워진다
- DB 결과와 자바 코드 구조가 자연스럽게 연결된다
즉 DTO는 “DB 한 줄을 자바 객체로 옮겨 담는 그릇”이다.
12. SQL을 XML로 분리
예제에서는 SQL을 자바 코드 안에 직접 쓰지 않고 XML 파일에 따로 작성했다.
<entry key="insertMenu">
INSERT INTO TBL_MENU (
MENU_NAME, MENU_PRICE, CATEGORY_CODE, ORDERABLE_STATUS
)
VALUES(?, ?, ?, ?)
</entry>
그리고 자바에서 이렇게 읽어왔다.
prop.loadFromXML(queryStream);
String query = prop.getProperty("insertMenu");
이 구조의 장점은:
- SQL과 자바 코드 분리
- 쿼리 수정이 쉬움
- 유지보수성이 높아짐
즉 규모가 커질수록 SQL을 외부 파일로 분리하는 방식이 더 중요해진다.
13. CRUD 중 INSERT, UPDATE, DELETE
CRUD 중 INSERT, UPDATE, DELETE 흐름도 함께 학습했다.
INSERT
result = pstmt.executeUpdate();
- 새로운 메뉴를 추가한다
- executeUpdate()는 변경된 행 수를 반환한다
UPDATE
- 메뉴 번호를 기준으로 이름과 가격을 수정한다
- 변경 대상 데이터를 MenuDTO에 담아 처리했다
DELETE
- 삭제 전에 먼저 메뉴를 조회하고
- 사용자에게 정말 삭제할지 확인한 뒤
- DELETE를 실행했다
이 흐름을 통해 단순히 SQL만 실행하는 것이 아니라,
사용자 입력 -> DTO -> SQL -> 결과 처리의 구조를 만드는 방식을 익혔다.
14. DAO 구조
예제의 중요한 부분은 MenuDAO였다.
public class MenuDAO {
public List<CategoryDTO> selectAllCategory(Connection con) { ... }
public int insertNewMenu(Connection con, MenuDTO newMenu) { ... }
}
DAO는 Database Access Object의 약자이다.
역할:
- 데이터베이스 접근 전담
- SQL 실행 담당
- CRUD 메서드 보관
즉 DAO는:
- 화면 입출력 코드와 DB 코드를 분리하고
- 데이터 접근 로직을 한 곳에 모으는 역할
을 한다.
이 구조가 중요한 이유는 애플리케이션 규모가 커질수록
DB 관련 코드를 여기저기 흩뿌리면 관리가 어려워지기 때문이다.
15. 카테고리 조회 후 메뉴 등록 흐름
- MenuDAO를 통해 등록 가능한 카테고리 목록 조회
- 사용자에게 메뉴 이름, 가격, 카테고리, 판매 여부 입력 받기
- 입력값을 MenuDTO에 담기
- insertNewMenu() 호출
- 결과에 따라 성공/실패 메시지 출력
이 구조를 통해 JDBC는 단순히 “DB 연결 연습”이 아니라
“작은 콘솔 애플리케이션 안에서 데이터 흐름을 설계하는 기술”이라는 점을 느낄 수 있었다.
16. 자원 반납의 중요성
JDBC에서는 사용한 자원을 반드시 닫아야 한다.
- ResultSet
- Statement / PreparedStatement
- Connection
예제에서도 항상 마지막에 닫아줬다.
close(rset);
close(pstmt);
close(con);
닫는 순서도 중요하다.
- 나중에 연 것부터 먼저 닫는다
- 보통 ResultSet -> Statement -> Connection
즉 JDBC에서는 자원 반납이 안정성과 성능에 매우 중요하다.
17. 학습 흐름 정리
17.1 연결과 설정
- JDBC 드라이버 로딩
- Connection 생성
- properties 파일로 접속 정보 분리
- JDBCTemplate로 공통 처리 정리
17.2 조회와 실행
- Statement로 기본 조회
- PreparedStatement로 안전한 조회
- ResultSet으로 결과 읽기
- SQL Injection 위험 확인
17.3 구조화
- DTO로 행 데이터를 객체화
- XML에 SQL 분리
- DAO로 DB 접근 로직 모으기
- CRUD 흐름을 콘솔 프로그램 형태로 확장
18. 핵심 정리
- JDBC는 자바 프로그램이 데이터베이스와 통신하기 위한 표준 API이다.
- Connection은 자바와 DB를 연결하는 통로이다.
- 접속 정보는 보통 properties 파일로 분리해서 관리한다.
- JDBCTemplate는 반복되는 연결/닫기 코드를 줄이기 위한 공통 클래스이다.
- Statement는 기본 SQL 실행 객체이지만, 사용자 입력 처리에는 취약할 수 있다.
- PreparedStatement는 SQL 구조와 입력값을 분리해 더 안전하게 실행한다.
- PreparedStatement는 SQL Injection 방어에 매우 중요하다.
- ResultSet은 조회 결과를 한 행씩 읽는 객체이다.
- DTO는 DB 한 행을 자바 객체로 담기 위한 구조이다.
- SQL을 XML 파일로 분리하면 유지보수성이 좋아진다.
- DAO는 데이터베이스 접근 로직을 한 곳에 모으는 역할을 한다.
- JDBC에서는 ResultSet, Statement, Connection을 반드시 닫아야 한다.
'TIL > [TIL]' 카테고리의 다른 글
| [TIL]Servlet JSON API에서 JDBC 연동까지: 프론트엔드, 서블릿, 서비스, DAO, DB 흐름 이해하기 (0) | 2026.05.21 |
|---|---|
| [TIL]Servlet 기초부터 요청/응답, 파라미터 처리, JSON API까지 (0) | 2026.05.20 |
| [TIL]JDBC 기초: 연결, Statement, PreparedStatement, SQL Injection, CRUD 흐름 (0) | 2026.05.18 |
| [TIL]SQL 심화: GROUP BY, 서브쿼리, 집합 연산, DML, 트랜잭션, DDL, 제약조건, 데이터 타입, 인덱스 (1) | 2026.05.15 |
| [TIL]SQL 조회 기초: SELECT, ORDER BY, WHERE, DISTINCT, LIMIT, JOIN (0) | 2026.05.14 |