Back-End

[JAVA] SQL과 JAVA를 합친 JDBC

Minch13r 2025. 2. 18. 21:36

2025.02.18 JDBC를 MVC로 나누어 공부해봤다.

 

JDBC란?

JDBC는 자바 프로그램이 데이터베이스와 대화할 수 있게 해주는 통역사 같은 역할을 한다.. 마치 외국인 친구와 대화할 때 통역사가 필요한 것처럼, 자바와 데이터베이스 사이에도 JDBC라는 통역사가 필요하다.

 

1. JDBC의 주요 구성요소

 

1) DriverManager

  • 데이터베이스 드라이버를 관리하는 매니저 역할이다.
  • 마치 택시 배차 센터처럼 적절한 드라이버를 찾아서 연결해준다.

2) Connection

  • 데이터베이스와의 실제 연결을 담당한다.
  • 마치 전화선처럼 자바 프로그램과 데이터베이스를 이어주는 통로다.

3) Statement/PreparedStatement

  • SQL 명령어를 데이터베이스에 전달하는 역할을 한다.
  • PreparedStatement는 SQL 인젝션을 방지하는 더 안전한 방법이다.

4) ResultSet

  • 데이터베이스에서 가져온 결과를 저장하는 곳이다.
  • 엑셀 시트처럼 행과 열로 구성되어 있다.

 

2. JDBC 사용 기본 단계

  1. 드라이버 로드하기
    • 데이터베이스와 대화하기 위한 준비를 한다.
  2. 데이터베이스 연결하기
    • 데이터베이스 주소, 아이디, 비밀번호를 이용해 연결한다.
  3. SQL 명령 준비 및 실행
    • 원하는 데이터베이스 작업을 수행한다.
  4. 결과 처리하기
    • 데이터베이스에서 받은 결과를 처리한다.
  5. 연결 닫기
    • 사용이 끝난 자원을 정리한다.

 

3. JDBC 사용시 주의사항

  1. 자원 관리
    • Connection, Statement, ResultSet은 반드시 닫아주어야 한다.
    • try-with-resources 구문 사용을 권장한다.
  2. 예외 처리
    • SQL 관련 예외들을 적절히 처리해야 한다.
    • 데이터베이스 연결 실패, SQL 문법 오류 등을 고려해야 한다.
  3. 커넥션 풀 사용
    • 많은 연결이 필요할 때는 커넥션 풀을 사용하면 좋다.
    • HikariCP 같은 커넥션 풀 라이브러리를 추천한다.

 

4. 실제 활용 예시 상황

  1. 회원 관리 시스템
    • 회원 정보 저장, 조회, 수정, 삭제
  2. 쇼핑몰 주문 시스템
    • 상품 정보 관리, 주문 처리, 재고 관리
  3. 게시판 시스템
    • 게시글 작성, 조회, 수정, 삭제

소스코드

Client

더보기
public class Client {
    public static void main(String[] args) {
        Controller app = new Controller();
        app.startApp();
    }
}

 

Controller

더보기
public class Controller {
    private BoardDAO boardDAO;
    private MemberDAO memberDAO;
    private View view;
    private MemberDTO user; // 로그인 여부
    public Controller() {
        this.boardDAO = new BoardDAO();
        this.memberDAO = new MemberDAO();
        this.view = new View();
        this.user = null; // 초기에는 비로그인 상태
    }

    public void startApp() {
        while(true) {
            if(user != null) { // 로그인 상태라면
                view.printMenuLogin();
            }
            else {
                view.printMenuLogout();
            }
            int action=view.inputAction();
            if(action==1) {
                if(user == null) {
                    continue;
                }

                String name=view.inputName();

                MemberDTO dto=new MemberDTO();
                dto.setMember_name(name); // 사용자가 입력한 이름 정보
                dto.setMember_id(user.getMember_id()); // 현재 로그인한 아이디 정보

                boolean flag=memberDAO.update(dto);
                if(flag) {
                    user=null; // 로그아웃 강제
                }
                view.printResult(flag);
            }
            else if(action==2) {
                if(user == null) {
                    continue;
                }

                BoardDTO dto=new BoardDTO();
                dto.setCondition("UPDATE_DELETEMEMBER");
                dto.setWriter(user.getMember_id());
                boardDAO.update(dto);
                boolean flag=memberDAO.delete(user);
                if(flag) {
                    user=null; // 로그아웃 강제
                }
                view.printResult(flag);
            }
            else if(action==3) {
                if(user == null) {
                    continue;
                }

                BoardDTO dto=view.inputBoardDTO();
                dto.setWriter(user.getMember_id());
                boolean flag=boardDAO.insert(dto);
                view.printResult(flag);
            }
            else if(action==4) {
                if(user == null) {
                    continue;
                }

                int num = view.inputAction();
                BoardDTO dto=new BoardDTO();
                dto.setNum(num);
                BoardDTO data=boardDAO.selectOne(dto);
                view.printData(data);

                if(data.getWriter().equals(user.getMember_id())) { // 본인인증
                    String content=view.inputContent();
                    dto=new BoardDTO();
                    dto.setNum(num);
                    dto.setContent(content);
                    dto.setCondition("UPDATE");
                    boolean flag=boardDAO.update(dto);
                    view.printResult(flag);
                }
            }
            else if(action==5) {
                if(user == null) {
                    continue;
                }

                int num = view.inputAction();
                BoardDTO dto=new BoardDTO();
                dto.setNum(num);
                boolean flag=boardDAO.delete(dto);
                view.printResult(flag);
            }
            else if(action==6) {
                if(user == null) {
                    continue;
                }

                user=null;
            }
            else if(action==7) {
                if(user != null) {
                    continue;
                }

                MemberDTO memberDTO=view.inputMemberDTO();
                boolean flag=memberDAO.insert(memberDTO);
                view.printResult(flag);
            }
            else if(action==8) {
                if(user != null) {
                    continue;
                }

                MemberDTO memberDTO=view.login();
                MemberDTO data=memberDAO.selectOne(memberDTO);
                if(data==null) {
                    view.printResult(false);
                }
                else {
                    this.user = data;
                    this.user.setMember_password(null);
                    view.printResult(true);
                }
            }
            else if(action==9) {
                BoardDTO dto=new BoardDTO();
                dto.setCondition("SELECTALL");
                view.printDatas(boardDAO.selectAll(dto));
            }
            else if(action==10) {
                action = view.inputAction();
                BoardDTO dto=null;
                if(action == 1) {
                    // 작성자 검색
                    String name = view.inputName();
                    dto=new BoardDTO();
                    dto.setCondition("SEARCH_WRITER");
                    dto.setSearchKeyword(name);
                }
                else {
                    // 제목 검색
                    String title = view.inputTitle();
                    dto=new BoardDTO();
                    dto.setCondition("SEARCH_TITLE");
                    dto.setSearchKeyword(title);
                }
                ArrayList<BoardDTO> datas=boardDAO.selectAll(dto);
                view.printDatas(datas);
            }
            else {
                break;
            }
        }
    }
}

 

Model

BoardDAO

더보기
package javastudy.day026.model.board;

import javastudy.day026.model.common.JDBCUtil;

import java.sql.*;
import java.util.ArrayList;

// 목록출력
// 검색
public class BoardDAO {
    final String SELECTALL = "SELECT NUM,TITLE,CONTENT,WRITER,CNT,REGDATE FROM BOARD";

    final String SELECTALL_SEARCH_TITLE = "SELECT NUM,TITLE,CONTENT,WRITER,CNT,REGDATE FROM BOARD WHERE TITLE LIKE CONCAT('%',?,'%')";
    final String SELECTALL_SEARCH_WRITER = "SELECT NUM,TITLE,CONTENT,WRITER,CNT,REGDATE FROM BOARD WHERE WRITER=?";

    //final String SELECTONE = "SELECT NUM,TITLE,CONTENT,WRITER,CNT,REGDATE FROM BOARD WHERE NUM=?";
    final String SELECTONE = "SELECT BOARD.NUM,BOARD.TITLE,BOARD.CONTENT,BOARD.WRITER,MEMBER.MEMBER_NAME AS NAME,BOARD.CNT,BOARD.REGDATE FROM BOARD LEFT JOIN MEMBER ON BOARD.WRITER=MEMBER.MEMBER_ID WHERE BOARD.NUM=?";

    final String INSERT = "INSERT INTO BOARD (TITLE,CONTENT,WRITER) VALUES(?,?,?)";
    final String UPDATE = "UPDATE BOARD SET CONTENT=? WHERE NUM=?";
    final String UPDATE_DELETEMEMBER = "UPDATE BOARD SET WRITER='' WHERE WRITER=?";
    final String DELETE = "DELETE FROM BOARD WHERE NUM=?";
    final String UPDATE_CNT = "UPDATE BOARD SET CNT=CNT+1 WHERE NUM=?";


    public ArrayList<BoardDTO> selectAll(BoardDTO dto){
        ArrayList<BoardDTO> datas=new ArrayList<BoardDTO>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();
            if(dto.getCondition().equals("SELECTALL")) {
                pstmt = conn.prepareStatement(SELECTALL);
            }
            else if(dto.getCondition().equals("SEARCH_TITLE")) {
                pstmt = conn.prepareStatement(SELECTALL_SEARCH_TITLE);
                pstmt.setString(1, dto.getSearchKeyword());
            }
            else if(dto.getCondition().equals("SEARCH_WRITER")) {
                pstmt = conn.prepareStatement(SELECTALL_SEARCH_WRITER);
                pstmt.setString(1, dto.getSearchKeyword());
            }
            ResultSet rs = pstmt.executeQuery();
            while(rs.next()) {
                BoardDTO data = new BoardDTO();
                data.setNum(rs.getInt("NUM"));
                data.setTitle(rs.getString("TITLE"));
                data.setContent(rs.getString("CONTENT"));
                data.setWriter(rs.getString("WRITER"));
                data.setCnt(rs.getInt("CNT"));
                data.setRegdate(rs.getDate("REGDATE"));
                datas.add(data);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
        return datas;
    }
    public BoardDTO selectOne(BoardDTO dto){
        BoardDTO data = null;
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();
            // 데이터 read, write
            pstmt = conn.prepareStatement(SELECTONE);
            pstmt.setInt(1, dto.getNum());
            ResultSet rs = pstmt.executeQuery();
            if(rs.next()) {
                data = new BoardDTO();
                data.setNum(rs.getInt("NUM"));
                data.setTitle(rs.getString("TITLE"));
                data.setContent(rs.getString("CONTENT"));
                data.setWriter(rs.getString("WRITER"));
                data.setName(rs.getString("NAME"));
                data.setCnt(rs.getInt("CNT"));
                data.setRegdate(rs.getDate("REGDATE"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
        return data;
    }
    public boolean insert(BoardDTO dto){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();
            // 데이터 read, write
            pstmt = conn.prepareStatement(INSERT);
            pstmt.setString(1, dto.getTitle());
            pstmt.setString(2, dto.getContent());
            pstmt.setString(3, dto.getWriter());
            int result = pstmt.executeUpdate();
            if(result <= 0) {
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
    }
    public boolean update(BoardDTO dto){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();

            // 조회수 증가
            pstmt = conn.prepareStatement(UPDATE_CNT);
            pstmt.setInt(1, dto.getNum());
            pstmt.executeUpdate();

            if(dto.getCondition().equals("UPDATE")) {
                pstmt = conn.prepareStatement(UPDATE);
                pstmt.setString(1, dto.getContent());
                pstmt.setInt(2, dto.getNum());
            }
            else if(dto.getCondition().equals("UPDATE_DELETEMEMBER")) {
                pstmt = conn.prepareStatement(UPDATE_DELETEMEMBER);
                pstmt.setString(1, dto.getWriter());
            }
            int result = pstmt.executeUpdate();
            if(result <= 0) {
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
    }
    public boolean delete(BoardDTO dto){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();
            // 데이터 read, write
            pstmt = conn.prepareStatement(DELETE);
            pstmt.setInt(1, dto.getNum());
            int result = pstmt.executeUpdate();
            if(result <= 0) {
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
    }
}

 

BoardDTO

더보기
package javastudy.day026.model.board;

import java.util.Date;

public class BoardDTO {
    private int num;
    private String title;
    private String content;
    private String writer; // FK : 상대 테이블의 PK ▶ JOIN으로 데이터 불러오기 가능
    private int cnt;
    private Date regdate;

    private String name; // JOIN으로 받아올 데이터
    private String condition;
    private String searchKeyword;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCondition() {
        return condition;
    }
    public void setCondition(String condition) {
        this.condition = condition;
    }
    public String getSearchKeyword() {
        return searchKeyword;
    }
    public void setSearchKeyword(String searchKeyword) {
        this.searchKeyword = searchKeyword;
    }

    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String getWriter() {
        return writer;
    }
    public void setWriter(String writer) {
        this.writer = writer;
    }
    public int getCnt() {
        return cnt;
    }
    public void setCnt(int cnt) {
        this.cnt = cnt;
    }
    public Date getRegdate() {
        return regdate;
    }
    public void setRegdate(Date regdate) {
        this.regdate = regdate;
    }

    @Override
    public String toString() {
        return "BoardDTO [num=" + num + ", title=" + title + ", content=" + content + ", writer=" + writer + ", cnt="
                + cnt + ", regdate=" + regdate + "]";
    }
}

 

JDBCUtil

더보기
package javastudy.day026.model.common;

import java.sql.*;

public class JDBCUtil {
    static final String driverName = "com.mysql.cj.jdbc.Driver";
    static final String url = "jdbc:mysql://localhost:3306/test";
    static final String userName = "root";
    static final String password = "12345678";

    public static Connection connect(){
        Connection conn = null;
        try {
            // 1. 드라이버 연결
            Class.forName(driverName);
            // 2. conn 연결
            conn = DriverManager.getConnection(url, userName, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    public static void disconnect(Connection conn, PreparedStatement pstmt){
        // 4. DB 연결 해제
        try {
            pstmt.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

MemberDAO

더보기
package javastudy.day026.model.member;

import javastudy.day026.model.common.JDBCUtil;

import java.sql.*;
import java.util.ArrayList;

public class MemberDAO {
    final String SELECTONE = "SELECT * FROM MEMBER WHERE MEMBER_ID=? AND MEMBER_PASSWORD=?";

    final String INSERT = "INSERT INTO MEMBER VALUES(?,?,?)";
    final String UPDATE = "UPDATE MEMBER SET MEMBER_NAME=? WHERE MEMBER_ID=?";
    final String DELETE = "DELETE FROM MEMBER WHERE MEMBER_ID=?";

    private ArrayList<MemberDTO> selectAll(MemberDTO dto){
        return null;
    }
    public MemberDTO selectOne(MemberDTO dto){
        MemberDTO data = null;
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();
            // 3. 데이터 read, write
            pstmt = conn.prepareStatement(SELECTONE);
            pstmt.setString(1, dto.getMember_id());
            pstmt.setString(2, dto.getMember_password());
            ResultSet rs = pstmt.executeQuery();
            if(rs.next()) {
                data=new MemberDTO();
                data.setMember_id(rs.getString("MEMBER_ID"));
                data.setMember_password(rs.getString("MEMBER_PASSWORD"));
                data.setMember_name(rs.getString("MEMBER_NAME"));
            }
            return data;
        } catch (Exception e) {
            e.printStackTrace();
            return data;
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
    }
    public boolean insert(MemberDTO dto){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();
            // 3. 데이터 read, write
            pstmt = conn.prepareStatement(INSERT);
            pstmt.setString(1, dto.getMember_id());
            pstmt.setString(2, dto.getMember_password());
            pstmt.setString(3, dto.getMember_name());
            int result = pstmt.executeUpdate();
            if(result <= 0) {
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
    }
    public boolean update(MemberDTO dto){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();
            // 3. 데이터 read, write
            pstmt = conn.prepareStatement(UPDATE);
            pstmt.setString(1, dto.getMember_name());
            pstmt.setString(2, dto.getMember_id());
            int result = pstmt.executeUpdate();
            if(result <= 0) {
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
    }
    public boolean delete(MemberDTO dto){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtil.connect();
            // 3. 데이터 read, write
            pstmt = conn.prepareStatement(DELETE);
            pstmt.setString(1, dto.getMember_id());
            int result = pstmt.executeUpdate();
            if(result <= 0) {
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            JDBCUtil.disconnect(conn, pstmt);
        }
    }
}

 

MemberDTO

더보기
package javastudy.day026.model.member;

public class MemberDTO {
    private String member_id;
    private String member_password;
    private String member_name;

    public String getMember_id() {
        return member_id;
    }
    public void setMember_id(String member_id) {
        this.member_id = member_id;
    }
    public String getMember_password() {
        return member_password;
    }
    public void setMember_password(String member_password) {
        this.member_password = member_password;
    }
    public String getMember_name() {
        return member_name;
    }
    public void setMember_name(String member_name) {
        this.member_name = member_name;
    }

    @Override
    public String toString() {
        return "MemberDTO [member_id=" + member_id + ", member_password=" + member_password + ", member_name="
                + member_name + "]";
    }
}

 


코드 설명

코드의 전반적인 내용은 DB와 연동해서 IDE Console을 이용한 커뮤니티 웹이다. 기능으로는 글 검색, 글 작성, 선택, 수정, 삭제, 회원탈퇴 등 다양하게 이루어진다.

 

데이터베이스는 MYSQL을 사용했다. JDBC를 통해 연동했는데 중복되는 처리 부분은 JDBCUtil 자바 클래스 파일을 새로 파 정리해두고 모듈화를 시켜 유지보수성을 향상시켰다.

 

SQL문을 확인해보면 값을 집어넣는 곳은 전부 물음표(?)로 이루어져 있는데 이 부분은 Java에서 코드 작업을 통해 값을 넣어주면 된다. 이렇게 DTO 값을 가져와 쿼리문에 넣어지면 높은 응집도와 낮은 결합도를 유지할 수 있다. 

 

공부하는 차원에서 진행해 UI/UX는 챙기지 못했지만 커뮤니티 웹 기초에 대해 알 수 있는 소중한 경험이였다.

 

테이블을 팔 때 PK와 FK를 필수적으로 잘 정해두고 정리해둬야 나중에 JDBC를 연동할 때 수월하게 진행될 수 있다.

'Back-End' 카테고리의 다른 글

[JSP/Servlet] 웹개발 기초 1  (0) 2025.02.26
[JSP/Servlet] 웹개발 기초  (1) 2025.02.20
[JAVA] 오답노트 및 발표 피드백  (1) 2025.02.17
[JAVA] Toy-Project  (1) 2025.02.07
[크롤링] Jsoup과 Selenium  (3) 2025.02.01