Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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
Tags
more
Archives
Today
Total
관리 메뉴

dearbeany

[JDBC] 게시판 만들기 (3. DBUtil 클래스 생성 ~ 4. CRUD 완성 및 테스트) 본문

Web

[JDBC] 게시판 만들기 (3. DBUtil 클래스 생성 ~ 4. CRUD 완성 및 테스트)

dearbeany 2022. 9. 25. 20:05

3. DBUtil 클래스 생성

→ DBUtil을 그 때마다 new 로 생성하지 말고, 한 번 생성해놓고 계속 쓰도록 하자. 싱글턴을 사용해서!

	private static DBUtil instance = new DBUtil();

	private DBUtil() {
	}

	public static DBUtil getInstace() {
		return instance;
	}

- DBUtil을 사용할 준비가 되었으니, JDBCTest.java의 역할을 DBUtil로 빼서 작성해보도록 하자.

public class DBUtil {

	// MySql 드라이버 클래스 이름
	private final String driverName = "com.mysql.cj.jdbc.Driver";
	// DB와 연결하기 위해 필요한 URL
	private final String url = "jdbc:mysql://localhost:3306/dearbeany_board?serverTimezone=UTC";
	// USER 정보
	private final String username = "DB연결할 유저의 아이디";
	private final String password = "DB연결할 유저의 비밀번호";

	private static DBUtil instance = new DBUtil();

	private DBUtil() {
		// JDBC 드라이버를 로딩
		try {
			Class.forName(driverName);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static DBUtil getInstace() {
		return instance;
	}

	/**
	 * DriverManager를 통해 내 userid, password를 이용해 Connection을 반환하는 메서드
	 * 
	 * @return Connection
	 * @throws SQLException
	 */
	public Connection getConnection() throws SQLException {
		return DriverManager.getConnection(url, username, password);
	}

	// ...가변인자를 사용하여 값이 몇개가 넘어오든 알아서 묶어서 반복할 수 있게끔 알아서 처리한다
	public void close(AutoCloseable... autoCloseables) {
		for (AutoCloseable ac : autoCloseables) {
			if (ac != null) {
				try {
					ac.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}

 


4.DAO 를 통해 CRUD 하기

- 직접적으로 DB와 Java가 소통할 수 있도록 왔다갔다하게 하는 역할DAO(Data Access Object) 라고 한다.

- DAO 인터페이스(BoardDao.java)와 이를 implements한 클래스(BoardDaoImpl.java)를 생성하도록 하자.

- 참고로 인터페이스에서는 메소드의 선언을, 클래스에서는 메소드의 구현을 한다.

더보기
cf. 인터페이스의 역할?
- 강제로 기능을 구현하게 한다
- 다형성, 추상화
- 나중에 다른 구현을 했을 때 갈아끼기 쉽다.

 

 

BoardDao.java

 

- 다음과 같이 CRUD 역할을 하는 6개의 메소드를 구현할 것이다. 각각의 역할에 해당하는 메소드는 다음과 같다.

  • C(Create) : insertBoard
  • R(Read) : selectAll, selectOne
  • U(Update) : updateBoard, updateViewCnt
  • D(Delete) : deleteBoard

 

 

public interface BoardDao {
	// 전체 게시판의 내용(게시글) 다 가져온다
	public List<Board> selectAll();

	// ID에 해당하는 게시글 하나 가져온다
	public Board selectOne(int id);

	// 게시글을 등록한다
	public void insertBoard(Board board);

	// 게시글을 삭제한다
	public void deleteBoard(int id);

	// 게시글을 수정한다
	public void updateBoard(Board board);

	// 조회수를 증가한다
	public void updateViewCnt(int id);
}

 


* 본격적으로 메소드를 구현하기 전에 주의할 점이 존재한다. (지난 포스팅 참고)

2022.09.25 - [분류 전체보기] - [JDBC] JDBC의 작업순서 | 게시판 만들기 실습 (1.board 테이블 설계 ~ 2.Java 프로젝트 생성)

 

 

* Statement vs PreparedStatement 차이?

- Statement는 sql문을 미리 완성해놓고 날려야 하나,

- PreparedStatement는 물음표를 이용하여 동적으로 원하는 값을 집어넣을 수가 있다.

 

 

* executeQuery vs exeCuteUpdate 차이?

- 바로 JDBC의 작업순서 중 (3)단계인데, CRUD의 역할에 따라 2개의 메소드(executeQuery, executeUpdate)가 존재하는 것이다.

- executeQuery의 경우 R(read)를 하기 때문에 반환되는 결과값인 ResultSet을 꼭 활용한다. 즉, SELECT의 경우 해당!

- 반면 executeUpdate의 경우 C, R, D에선 결과값을 반환할 필요가 없다.

 

 

BoardDaoImpl.java

1. insertBoard() 메소드를 작성해보도록 하자. (CRUD 중 Create)

	public void insertBoard(Board board) throws SQLException {
		// 미리 sql 문 만들어 놓고 PreparedStatement 객체를 만들어서
		// ?에 대신 값을 채우도록 하자
		String sql = "INSERT INTO board (title, writer, content) VALUES (?,?,?)";

		// DB 접속해서 사용하게끔 쓰자
		Connection conn = null;
		PreparedStatement pstmt = null;

		try {
			conn = util.getConnection();
			pstmt = conn.prepareStatement(sql);

			pstmt.setString(1, board.getTitle()); // 첫 번째 물음표에 board가 가진 title 값을 세팅
			pstmt.setString(2, board.getWriter()); // 두 번째 물음표에 board가 가진 writer 값을 세팅
			pstmt.setString(3, board.getContent()); // 세 번째 물음표에 content 값을 세팅

			pstmt.executeUpdate(); // 데이터를 변경해야 하므로 update를 날린다
			// stmt.executeQuery(sql) 와는 다르다. 이미 sql문을 위에 다 만들어놓고 데이터 변경만 하면 되기 때문

		} finally {
			util.close(pstmt, conn);
		}
	}

 

 

 

insertBoard() 메소드를 테스트 해보면?

public class Test {
	public static void main(String[] args) {
		BoardDao dao = BoardDaoImpl.getInstace();

		Board board = new Board("빠르게 실패하기", "존 크럼볼츠", "빠르게 성공하고 싶은 법을 알려준다");

		try {
			dao.insertBoard(board);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

Test 파일을 Run하고 워크벤치에서 SELECT로 조회해본다.

아래와 같이 데이터가 잘 추가된 것을 확인해볼 수 있다!

 

 

 

 

*** MySql은 자동으로 AutoCommit이 설정되어있다.

 

 


2.  selectAll() 메소드도 완성해보자. (CRUD 중 Read)

	public List<Board> selectAll() {
		String sql = "SELECT * FROM board";
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;

		List<Board> list = new ArrayList<>();
		try {
			conn = util.getConnection();
			stmt = conn.createStatement();
			rs = stmt.executeQuery(sql);

			while (rs.next()) {
				int id = rs.getInt("id");
				String writer = rs.getString("writer");
				String title = rs.getString("title");
				String content = rs.getString("content");
				int viewCnt = rs.getInt("view_cnt");
				String regDate = rs.getString("reg_date");

				Board board = new Board(id, title, writer, content, regDate, viewCnt);

				list.add(board);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			util.close(rs, stmt, conn);
		}

		return list;
	}

이를 Test 파일에서 메소드를 호출하여 결과를 출력해보면?

다음과 같이 모두 조회되는 것을 확인해볼 수 있다.

 

 

 


 

3. selectOne() 메소드 (CRUD 중 Read)

	public Board selectOne(int id) {
		String sql = "SELECT * FROM board WHERE id = ?";
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		Board board = new Board();

		try {
			conn = util.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, id);
			rs = pstmt.executeQuery();

			while (rs.next()) {
				board.setId(rs.getInt(1));
				board.setWriter(rs.getString(2));
				board.setTitle(rs.getString(3));
				board.setContent(rs.getString(4));
				board.setViewCnt(rs.getInt(5));
				board.setRegDate(rs.getString(6));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			util.close(conn, pstmt, rs);
		}

		return board;
	}

id가 1인 게시글을 확인해보자. 아래와 같이 잘 출력되는 것을 확인할 수 있다.

 


 

 

4. deleteBoard() - CRUD 중 D(delete)

	public void deleteBoard(int id) throws SQLException {
		String sql = "DELETE FROM board WHERE id = ?";
		Connection conn = null;
		PreparedStatement pstmt = null;

		try {
			conn = util.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, id); // 첫 번째 자리에 id를 넣는다
			pstmt.executeUpdate();
		} finally {
			util.close(pstmt, conn);
		}
	}

 

id가 3인 게시글을 삭제하니 다음과 같이 잘 출력되는 것을 확인할 수 있다.

 

 


 

 

5. updateViewCnt() - CRUD 중 U(update)

	public void updateViewCnt(int id) throws SQLException {
		String sql = "UPDATE board SET view_cnt = view_cnt+1 WHERE id = ?";
		Connection conn = null;
		PreparedStatement pstmt = null;

		try {
			conn = util.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, id);
			pstmt.executeUpdate();
		} finally {
			util.close(pstmt, conn);
		}
	}

id가 2인 게시글에 대하여 메소드를 실행하였다. 파일을 2번 Run하니, id 가 2인 게시글의 ViewCnt가 2로 증가했음을 확인할 수 있다.

 


 

6. updateBoard() - CRUD 중 U(update)

- 게시글에 대하여 title과 content를 바꾸도록 한다. 

	public void updateBoard(Board board) throws SQLException {
		String sql = "UPDATE board SET title = ?, content = ? WHERE id = ?";
		Connection conn = null;
		PreparedStatement pstmt = null;

		try {
			conn = util.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, board.getTitle());
			pstmt.setString(2, board.getContent());
			pstmt.setInt(3, board.getId());
			pstmt.executeUpdate();
		} finally {
			util.close();
		}
	}

 

Test.java에서 테스트 해보자!

public class Test {
	public static void main(String[] args) {
		BoardDao dao = BoardDaoImpl.getInstace();

		Board board = dao.selectOne(2); // id가 2번인 게시글을 가져온다
		try {
			// title, content 를 변경하고
			board.setTitle("불편한 편의점1");
			board.setContent("청파동을 배경으로 한 김호연의 신간");
			// 변경한 내용으로 update 하기
			dao.updateBoard(board);
		} catch (SQLException e) {
			e.printStackTrace();
		}

		// 전체 게시판 글을 모두 출력해보면
		for (Board b : dao.selectAll()) {
			System.out.println(b);
		}
	}
}

다음과 같이 업데이트 된 내용을 출력할 수 있다.