model.dao에서 자주 사용되는
CRUD 메서드를 상황에 맞춰
가져다 쓰기 좋게 정리해보았다.
[공통사항 - 멤버변수/공유자원]
해당 BAO에서 어떤 쿼리문이 사용되는지를
우선적으로 파악하고 싶어하기 때문에!
쿼리문을 최상단에 올리게 되는데,
이런 경우에 멤버변수/공유자원에 해당된다.
멤버변수는 보통 생성자를 통해 초기화하는데
생성자 없이 초기화를 하였으므로 쿼리문은
공유자원이 되어 static을 사용하여 표기한다.
▼ DAO 클래스 공유자원 쿼리문 선언
public class BoardDAO {
private static final String SELECT_ALL = "SELECT * FROM BOARD ORDER BY BID DESC";
private static final String SELECT_ALL_TITLE = "SELECT * FROM BOARD WHERE TITLE LIKE ? ORDER BY BID DESC";
private static final String SELECT_ALL_MID = "SELECT * FROM BOARD WHERE MID = ? ORDER BY BID DESC";
private static final String SELECT_ALL_BCOUNT = "SELECT * FROM BOARD ORDER BY BCOUNT DESC, BID DESC";
private static final String SELECT_ONE = "SELECT * FROM BOARD WHERE BID = ?";
private static final String INSERT = "INSERT INTO BOARD(BID,TITLE,CONTENT,MID) VALUES((SELECT NVL(MAX(BID),100) FROM BOARD)+1,?,?,?)";
private static final String DELETE = "DELETE FROM BOARD WHERE BID = ?";
private static final String UPDATE_BCOUNT = "UPDATE BOARD SET BCOUNT = BCOUNT+1 WHERE BID = ?";
private static final String UPDATE_TITLE = "UPDATE BOARD SET TITLE = ? WHERE BID = ?";
private static final String UPDATE_CONTENT = "UPDATE BOARD SET CONTENT = ? WHERE BID = ?";
JDBC 활용을 하다보면 CRUD 생성 과정에서
1,2,4단계는 똑같고 3단계만 필요에 따라
바꿔주는 상황이 계속 반복되고 있다.
그래서 코드 결합도를 고려해 1,2,4를
함수화, 모듈화, 컴포넌트화 하면 좋겠다.
> 즉 메서드로 처리하면 된다!
이를 위해 로직을 담을 별도의 Util 클래스를 만들어보자.
[JDBCUtil class]
▼ model common(공용) 로직 클래스 코딩
package model.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
// Util류 클래스들이 대체적으로 static(객체와 무관하게) 메서드를 로직으로 품고있어서 메서드만 호출하여 사용하는 경우가 多
public class JDBCUtil {
private static final String driverName = "oracle.jdbc.driver.OracleDriver";
private static final String url = "jdbc:oracle:thin:@localhost:1521:xe";
private static final String user = "TEEMO";
private static final String password = "1234";
//driverName, url, user, password가 달라질때마다 util 클래스가 추가되어야한다.
// 1,2 ▶ 함수화,모듈화,컴포넌트화
public static Connection connect() {
Connection conn = null;
try {
// 1. 드라이버 로드(적재)
Class.forName(driverName);
// 2. DB 연결
conn = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
// 4 ▶ 함수화,모듈화,컴포넌트화
public static void disconnect(Connection conn,PreparedStatement pstmt) {
try {
// 4. DB 연결 해제
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
[Create] - 추가
인자로 받은 객체에서 정보를 꺼내
pstmt에 세터를 적용시키고 DB에 추가한다.
이후 성공 실패 유무를 반환한다.
▼ Create(=insert) 메서드 코딩
public boolean insert(BoardDTO boardDTO){
// DB 연결 얻기
Connection conn = JDBCUtil.connect();
// PreparedStatement는 finally에서 닫기 위해 try 바깥에서 선언
PreparedStatement pstmt = null;
try {
// 미리 정의된 INSERT SQL로 PreparedStatement 생성
pstmt = conn.prepareStatement(INSERT);
// SQL 내 첫 번째 ? 에 title 값을 바인딩
pstmt.setString(1, boardDTO.getTitle());
// 두 번째 ? 에 content 값을 바인딩
pstmt.setString(2, boardDTO.getContent());
// 세 번째 ? 에 작성자 ID(mid) 값을 바인딩
pstmt.setString(3, boardDTO.getMid());
// INSERT, UPDATE, DELETE 계열은 executeUpdate() 호출 — 변경된 행(row) 수를 반환
int result = pstmt.executeUpdate();
// result는 영향을 받은 행의 수(정상적으로 1이 되어야 함)
// 0 이하면 삽입 실패로 간주하고 false 반환
if(result <= 0) {
return false;
}
} catch (SQLException e) {
// 예외 발생 시 스택트레이스 출력
e.printStackTrace();
// 예외 발생하면 실패로 처리
return false;
} finally {
// PreparedStatement와 Connection을 정리(닫기)
JDBCUtil.disconnect(conn, pstmt);
}
// 정상적으로 한 행이 삽입되었으면 true 반환
return true;
}
[Update] - 변경
업데이트 항목이 어떤 사항인지 분기점(Condition)과
equals 비교를 통해 확인, 확인 조건은 제어문으로 관리한다.
제어문이 종료되면 DB업데이트 결과를 받고
성공 실패 유무를 반환한다.
▼ Update 메서드 코딩
public boolean update(BoardDTO boardDTO){
// DB 연결 획득
Connection conn = JDBCUtil.connect();
PreparedStatement pstmt = null;
try {
// 어떤 UPDATE를 할지 조건문으로 구분
// (조건문에 따라 서로 다른 SQL을 사용)
// 조회수 증가(BCOUNT 업데이트)
if(boardDTO.getCondition().equals("UPDATE_BCOUNT")) {
pstmt = conn.prepareStatement(UPDATE_BCOUNT);
// ex) UPDATE BOARD SET BCOUNT = BCOUNT+1 WHERE BID = ?
// WHERE BID=?에 들어갈 파라미터 (게시글번호)
pstmt.setInt(1, boardDTO.getBid());
}
// 내용(Content) 수정
else if(boardDTO.getCondition().equals("UPDATE_CONTENT")) {
pstmt = conn.prepareStatement(UPDATE_CONTENT);
// ex) UPDATE BOARD SET CONTENT=? WHERE BID=?
pstmt.setString(1, boardDTO.getContent()); // CONTENT 값 바인딩
pstmt.setInt(2, boardDTO.getBid()); // BID 값 바인딩
}
// 제목(Title) 수정
else if(boardDTO.getCondition().equals("UPDATE_TITLE")) {
pstmt = conn.prepareStatement(UPDATE_TITLE);
// ex) UPDATE BOARD SET TITLE=? WHERE BID=?
pstmt.setString(1, boardDTO.getTitle()); // TITLE 값 바인딩
pstmt.setInt(2, boardDTO.getBid()); // BID 값 바인딩
}
// UPDATE 실행 → 영향 받은 row 수 반환
int result = pstmt.executeUpdate();
// 영향받은 행이 1 이상이어야 정상 처리
if(result <= 0) {
// 업데이트 실패한 경우
return false;
}
} catch (SQLException e) {
// DB 동작 중 예외 발생 → 실패 처리
e.printStackTrace();
return false;
} finally {
// PreparedStatement, Connection 정리
JDBCUtil.disconnect(conn, pstmt);
}
// 성공적으로 UPDATE 마무리된 경우 true
return true;
}
[Delete] - 삭제
삭제해야할 타겟을 탐색해야 하므로
PK값 기준으로 타겟을 찾게 된다.
넘겨받은 id(PK)를 활용하여 대상을 찾고
DB에서 삭제하거나 등급을 변경시킨 후
성공 실패 유무를 반환한다.
▼ Delete 메서드 코딩
public boolean delete(BoardDTO boardDTO){
// DB 연결 객체 얻기 ( Connection 생성 )
Connection conn = JDBCUtil.connect();
// PreparedStatement는 finally에서 닫아줘야 하므로 try 밖에서 선언
PreparedStatement pstmt = null;
try {
// DELETE SQL 준비
pstmt = conn.prepareStatement(DELETE);
// WHERE BID=? 에 들어갈 값 바인딩 (삭제할 게시글 번호)
pstmt.setInt(1, boardDTO.getBid());
// DELETE 실행 → 영향받은 row 수 반환
int result = pstmt.executeUpdate();
// 삭제된 행이 1개 이상이어야 정상 delete
if(result <= 0) {
return false; // 삭제 실패
}
} catch (SQLException e) {
// SQL 실행 중 오류가 발생했을 때
e.printStackTrace();
return false;
} finally {
// Connection, PreparedStatement 자원 정리
JDBCUtil.disconnect(conn, pstmt);
}
// 정상적으로 삭제되었을 경우 true 반환
return true;
}
[R-All] - 전부 읽기(여러개 반환)
ALL을 반환해야 하기 때문에
반환할 배열을 먼저 만들어주고(datas)
인자에서 담긴 정보를 data객체에 담아
datas 배열에 넣어서 반환한다.
▼ Read All/Select All 메서드 코딩
public ArrayList<BoardDTO> selectAll(BoardDTO boardDTO){
// 조회결과들(여러 개)을 저장할 배열리스트 준비
ArrayList<BoardDTO> datas = new ArrayList<BoardDTO>();
// 1,2 ▶ DB연결을 별도클래스(JDBCUtil)에서 처리하게 만든 것 = 함수화, 모듈화 개념
Connection conn = JDBCUtil.connect();
// 3 PreparedStatement는 finally에서 닫아야하므로 try 밖에서 선언
PreparedStatement pstmt = null;
try {
// 조건에 따라 다른 SQL문을 사용
// getCondition() 값이 "ALL" 이면 전체조회용 SQL 사용
if(boardDTO.getCondition().equals("ALL")) {
pstmt = conn.prepareStatement(SELECT_ALL);
}
// 제목 검색 조건이면 제목을 조건으로 SQL을 사용
else if(boardDTO.getCondition().equals("TITLE")) {
pstmt = conn.prepareStatement(SELECT_ALL_TITLE);
pstmt.setString(1, boardDTO.getTitle());
// ★ 물음표(?)에 boardDTO의 title 값을 바인딩
}
// 작성자ID(mid)로 검색하는 조건
else if(boardDTO.getCondition().equals("MID")) {
pstmt = conn.prepareStatement(SELECT_ALL_MID);
pstmt.setString(1, boardDTO.getMid());
// ★ 작성자ID값 바인딩
}
// 조회수순 정렬 같은 조건
else if(boardDTO.getCondition().equals("BCOUNT")) {
pstmt = conn.prepareStatement(SELECT_ALL_BCOUNT);
}
// 쿼리 실행하고 결과집합(ResultSet)을 받음
ResultSet rs = pstmt.executeQuery();
// 결과집합을 순서대로 한줄씩 읽기
while(rs.next()) {
// 레코드 하나 → DTO 하나
BoardDTO data = new BoardDTO();
// DB컬럼에서 값을 꺼내서 DTO 객체에 담는다
data.setBid(rs.getInt("BID"));
data.setTitle(rs.getString("TITLE"));
data.setContent(rs.getString("CONTENT"));
data.setMid(rs.getString("MID"));
data.setBcount(rs.getInt("BCOUNT"));
// 완성된 DTO 한 개를 datas 리스트에 추가
datas.add(data);
}
} catch (SQLException e) {
// DB 수행도중 예외 발생 시 로그 출력
e.printStackTrace();
} finally {
// 4 ▶ DB연결 종료도 모듈화 시켜둔 함수 (자원정리)
JDBCUtil.disconnect(conn, pstmt);
}
// 완성된 결과리스트 리턴
return datas;
}
[R-One] - 한 개 읽기(1개만 반환)
One을 반환하기 때문에 datas가 아닌
객체 리턴이 된다. = return data;
찾아온 데이터가 있다면 (rs.next가 null이 아니라면)
그 데이터의 정보로 data 객체의 정보를 세터해서 반환한다.
▼ Read One/Select One 메서드 코딩
public BoardDTO selectOne(BoardDTO boardDTO){
// 조회 결과를 담을 변수
//조회 실패(레코드 없음) 시 null을 반환하도록 초기값을 null로 둠
BoardDTO data = null;
// DB 연결을 얻어오는 메서드
Connection conn = JDBCUtil.connect();
// PreparedStatement를 여기서 선언! finally 블록에서 닫기 위해 try 바깥에서 선언함
PreparedStatement pstmt = null;
try {
pstmt = conn.prepareStatement(SELECT_ONE);
// SQL의 첫 번째 물음표(?)에 파라미터를 설정
// 전달된 boardDTO의 bid(게시글 ID)를 이용해 조회 대상 레코드를 지정
pstmt.setInt(1, boardDTO.getBid());
// 쿼리 실행. SELECT문은 ResultSet을 반환
ResultSet rs = pstmt.executeQuery();
// ResultSet에서 한 행(row)이라도 존재하면 true.
// 존재하면 DTO를 만들어 값을 채워 반환 준비
if(rs.next()) {
// 조회 결과를 담을 DTO 객체 생성
data = new BoardDTO();
// 컬럼 이름으로 값을 꺼내어 DTO의 필드에 세팅
data.setBid(rs.getInt("BID"));
data.setTitle(rs.getString("TITLE"));
data.setContent(rs.getString("CONTENT"));
data.setMid(rs.getString("MID"));
data.setBcount(rs.getInt("BCOUNT"));
}
} catch (SQLException e) {
// SQL 실행 중 예외가 발생하면 스택트레이스를 출력.
e.printStackTrace();
} finally {
// JDBCUtil.disconnect(conn, pstmt)로 자원 정리를 수행.
JDBCUtil.disconnect(conn, pstmt);
}
// 조회 결과 DTO 반환. 레코드가 없으면 null 반환.
return data;
}
'개주 훈련일지 > 🏋️ 전집중 호흡 훈련' 카테고리의 다른 글
| 시퀀스와 최대 출력 제한 (0) | 2025.11.07 |
|---|---|
| 정규식 (0) | 2025.11.07 |
| hasType - 어떠한 배열에 어떠한 타입이 있니 (0) | 2025.10.28 |
| Java에서 txt 파일 읽기, 복사하기, 저장하기 (0) | 2025.10.25 |
| 줄바꿈을 입력하는 방법 (0) | 2025.10.24 |