[이것이 자바다] 20장 정리

자바에서 데이터베이스 입출력을 이해하고, 이를 바탕으로 데이터베이스에 접근하여 데이터를 추가, 읽기, 수정, 삭제하는 게시판 어플리케이션을 제작하는 방법을 설명합니다. 이 과정에서 JDBC를 이용한 데이터베이스 연결, SQL 쿼리 실행, ResultSet을 통한 데이터 읽기, 트랜잭션 처리 등의 핵심 개념과 메소드를 소개합니다.
Jan 25, 2024
[이것이 자바다] 20장 정리

ConnectionExam.java

package ch20; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class ConnectionExam { public static void main(String[] args) { Connection conn = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // 드라이버를 찾아주면 메모리에 스태틱 블록으로 올라간다. // ip, 포트, db명으로 db에 연결 / 계정 / 패스워드 conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/thisisjava", "java", "1234"); System.out.println("연결 성공"); // sql문 작성 String sql = new StringBuilder() .append("insert into users (userid, username, userpassword, userage, useremail) ") .append("values (?, ?, ?, ?, ?) ") .toString(); // PreparedStatement로 value에 들어갈 값 지정 PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, "winter"); pstmt.setString(2, "한겨울"); pstmt.setString(3, "12345"); pstmt.setInt(4, 25); pstmt.setString(5, "winter@mycompany.com"); // sql문 실행 int rows = pstmt.executeUpdate(); System.out.println("저장된 행 수: "+ rows); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { // 통상적으로 db 연결 후에는 db 연결 끊어줌 if (conn != null) { try { // 연결 끊기 conn.close(); System.out.println("연결 끊기"); } catch (SQLException e) { } } } } }
 

핵심 키워드

  • 클라이언트 프로그램을 DB와 연결하기 위해 가장 먼저 해야 할 작업은 JDBC Driver를 메모리로 로딩하는 것이다. Class.forName() 메소드는 문자열로 주어진 JDBC Driver 클래스를 Build Path에서 찾고, 메모리로 로딩한다.
    • Class.forName("com.mysql.cj.jdbc.Driver");
    • 이 과정에서 JDBC Driver 클래스의 static 블록이 실행되면서 DriverManager에 JDBC Driver 객체를 등록하게 된다. 만약 Build Path에서 JDBC Driver 클래스를 찾지 못하면 ClassNotFoundException이 발생하므로 예외 처리를 해야 한다.
  • DriverManager에 JDBC Driver가 등록되면 getConnection() 메소드로 DB와 연결을 할 수 있다.
    • Connection conn = DriverManager.getConnection("jdbc:mysql://IP주소:포트/db명", "사용자", "비밀번호");
  • 연결이 성공하면 getConnection() 메소드는 Connection 객체를 리턴한다. 만약 연결이 실패하 면 SQLException이 발생하므로 예외 처리를 해야 한다.
  • JDBC를 통해서 원하는 데이터를 데이터베이스에 저장하고 싶으면, INSERT문을 값을 ?(물음표)로 대체한 매개변수화된 INSERT 문으로 변경해서 실행한다.
    • String sql = new StringBuilder() .append("INSERT INTO users (userid, username, userpassword, userage, useremail) ") .append("VALUES (?, ?, ?, ?, ?)") .toString();
    • 매개변수화된 SQL 문을 실행하려면 PreparedStatement가 필요하다. 그리고 ?에 들어갈 값을 지정해주는데, ?는 순서에 따라 1번부터 번호가 부여된다. 값의 타입에 따라 Setter 메소드를 선택한 후 첫 번째에는 ? 순번, 두 번째에는 값을 지정해 준다.
      • PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, "winter"); pstmt.setString(2, "한겨울"); pstmt.setString(3, "12345"); pstmt.setInt(4, 25); pstmt.setString(5, "winter@mycompany.com");
    • 값을 지정한 후 executeUpdate() 메소드를 호출하면 SQL 문이 실행되면서 users 테이블에 1개 의 행이 저장된다. executeUpdate() 메소드가 리턴하는 값은 저장된 행 수인데, 정상적으로 실행 되었을 경우 1을 리턴한다.
      • int rows = pstmt.executeUpdate();
    • PreparedStatement를 더 이상 사용하지 않을 경우에는 close ( ) 메소드를 호출해서 PreparedStatement가 사용했던 메모리를 해제시킨다.
      • pstmt.close();
 

BoardInsertExam.java

package ch20; import java.io.FileInputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class BoardInsertExam { public static void main(String[] args) throws Exception { Connection conn = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // 드라이버를 찾아주면 메모리에 스태틱 블록으로 올라간다. // ip, 포트, db명으로 db에 연결 / 계정 / 패스워드 conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/thisisjava", "java", "1234"); System.out.println("연결 성공"); // sql문 작성 String sql = new StringBuilder() .append("insert into boards (btitle, bcontent, bwriter, bdate, bfilename, bfiledata) ") .append("values (?, ?, ?, now(), ?, ?) ") .toString(); // PreparedStatement로 value에 들어갈 값 지정 PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); pstmt.setString(1, "눈 오는 날"); pstmt.setString(2, "함박눈이 내려요"); pstmt.setString(3, "winter"); pstmt.setString(4, "image1.png"); pstmt.setBlob(5, new FileInputStream("src/ch20/image1.png")); // sql문 실행 int rows = pstmt.executeUpdate(); System.out.println("저장된 행 수: " + rows); if(rows == 1) { ResultSet rs = pstmt.getGeneratedKeys(); if(rs.next()) { int bno = rs.getInt(1); System.out.println("저장된 행의 키 값: "+ bno); } rs.close(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) { try { // 연결 끊기 conn.close(); System.out.println("연결 끊기"); } catch (SQLException e) { } } } } }
 

핵심 키워드

  • 매개변수화된 INSERT 문을 실행하기 위해 prepareStatement( ) 메소드로부터 PreparedStatement를 얻을 때, 두 번째 매개값을 넣으면 INSERT 문이 실행된 후 키 값을 가져올 수 있다.
    • PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
  • INSERT 문을 실행하고 저장된 키 값을 얻는 방법은, 게시물 정보가 저장되었을 경우(rows가 1일 경우) getGeneratedKeys () 메소드로 ResultSet을 얻고, getInt() 메소드로 기 값을 얻을 수 있다.
    • int rows = pstmt.executeUpdate(); //SQL 문 실행 if(rows = = 1) { ResultSet rs = pstmt.getGeneratedKeys(); //new String[] { "bno" }에 기술된 컬럼 값을 가져옴 if(rs.next()) { //값이 있다면 int bno = rs.getInt(1); //new String[] { "bno" }의 첫 번째 항목 bno 컬럼 값을 읽음 } rs.close(); //ResultSet이 사용했던 메모리 해제 }
 

BoardUpdateExam.java

package ch20; import java.io.FileInputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class BoardUpdateExam { public static void main(String[] args) throws Exception { Connection conn = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // 드라이버를 찾아주면 메모리에 스태틱 블록으로 올라간다. // ip, 포트, db명으로 db에 연결 / 계정 / 패스워드 conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/thisisjava", "java", "1234"); System.out.println("연결 성공"); // sql문 작성 String sql = new StringBuilder() .append("UPDATE boards SET ") .append("btitle=?, ") .append("bcontent=?, ") .append("bfilename=?, ") .append("bfiledata=? ") // 절의 마지막에는 ,를 붙이면 안된다. .append("where bno=? ") .toString(); PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, "눈사람"); pstmt.setString(2, "눈으로 만든 사람"); pstmt.setString(3, "image2.png"); pstmt.setBlob(4, new FileInputStream("src/ch20/image2.png")); pstmt.setInt(5, 5); // boards 테이블에 있는 게시물 번호(bno) 지정 pstmt.executeUpdate(); pstmt.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) { try { // 연결 끊기 conn.close(); System.out.println("연결 끊기"); } catch (SQLException e) { } } } } }
 

핵심 키워드

  • JDBC를 이용해서 UPDATE 문을 실행하려면 매개변수화된 UPDATE 문을 작성하고, 매개변수화된 UPDATE문을 실행하기 위해 prepareStatement() 메소드로부터 PreparedStatement를 얻고 값을 지정한 다음, executeUpdate() 메소드를 호출하면 된다.
    • String sql = new StringBuilder() .append("UPDATE boards SET ") .append("btitle= ?, ") .append("bcontent= ?, ") .append("bfilename= ?, ") .append("bfiledata= ? ") .append("WHERE bno= ?") .toString(); PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, "눈사람"); pstmt.setString(2, "눈으로 만든 사람"); pstmt.setString(3, "snowman.jpg"); pstmt.setBlob(4, new FileInputStream("src/ch20/mysql/sec07/snowman.jpg")); pstmt.setInt(5, 3); pstmt.executeUpdate();
 

BoardDeleteExam.java

package ch20; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class BoardDeleteExam { public static void main(String[] args) { Connection conn = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // 드라이버를 찾아주면 메모리에 스태틱 블록으로 올라간다. // ip, 포트, db명으로 db에 연결 / 계정 / 패스워드 conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/thisisjava", "java", "1234"); System.out.println("연결 성공"); // sql문 작성 String sql = "delete from boards where bwriter=?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, "winter"); int rows = pstmt.executeUpdate(); System.out.println("삭제된 행 수: "+rows); pstmt.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) { try { // 연결 끊기 conn.close(); System.out.println("연결 끊기"); } catch (SQLException e) { } } } } }
 

핵심 키워드

  • JDBC를 이용해서 DELETE문을 실행하려면 조건절의 값을 ?로 대체한 매개변수화된 DELETE 문을 작성하고, 매개변수화된 DELETE 문을 실행하기 위해 prepareStatement ( ) 메소드로부 PreparedStatement를 얻고 ?에 값을 지정한 후, executeUpdate로 SQL 문을 실행한다. 리턴값은 삭제된 행 수이다.
    • String sql = "DELETE FROM boards WHERE bwriter= ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, "winter"); int rows = pstmt.executeUpdate();
 

User.java

package ch20; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class User { private String userId; private String userName; private String userPassword; private int userAge; private String userEmail; }

UserSelectExam.java

package ch20; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class UserSelectExam { public static void main(String[] args) { Connection conn = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // 드라이버를 찾아주면 메모리에 스태틱 블록으로 올라간다. // ip, 포트, db명으로 db에 연결 / 계정 / 패스워드 conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/thisisjava", "java", "1234"); System.out.println("연결 성공"); String sql = "select * from users where userid=? "; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, "winter"); // sql문 실행 후, ResultSet을 통해 데이터 읽기 ResultSet rs = pstmt.executeQuery(); if(rs.next()) { // 비어있지 않을 경우 User user = new User( rs.getString("userid"), rs.getString("username"), rs.getString("userpassword"), rs.getInt(4), // 컬럼 순번을 이용할 수도 있다. rs.getString(5) ); System.out.println(user); }else { System.out.println("사용자 아이디가 존재하지 않음"); } rs.close(); pstmt.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) { try { // 연결 끊기 conn.close(); System.out.println("연결 끊기"); } catch (SQLException e) { } } } } }

Board.java

package ch20; import java.sql.Blob; import java.sql.Date; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class Board { private int bno; private String btitle; private String bcontent; private String bwriter; private Date bdate; private String bfilename; private Blob bfiledata; }

BoardSelectExam.java

package ch20; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class BoardSelectExam { public static void main(String[] args) { Connection conn = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // 드라이버를 찾아주면 메모리에 스태틱 블록으로 올라간다. // ip, 포트, db명으로 db에 연결 / 계정 / 패스워드 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/thisisjava", "java", "1234"); System.out.println("연결 성공"); String sql = """ select * from boards where bwriter=? """; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, "winter"); ResultSet rs = pstmt.executeQuery(); List<Board> list = new ArrayList<>(); while(rs.next()) { // 컬렉션에 일관적으로 값을 담고 Board board = new Board( rs.getInt(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getDate(5), rs.getString(6), rs.getBlob(7) ); list.add(board); } rs.close(); pstmt.close(); list.stream().forEach(e -> e.setBtitle("비 오는 날")); // 컬렉션에 담은 값을 변경 for(Board b : list) { String sql2 = """ update boards set btitle=? where bwriter=? """; PreparedStatement pstmt2 = conn.prepareStatement(sql2); pstmt2.setString(1, b.getBtitle()); pstmt2.setString(2, b.getBwriter()); int rows = pstmt2.executeUpdate(); // 업데이트 System.out.println(rows); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) { try { // 연결 끊기 conn.close(); System.out.println("연결 끊기"); } catch (SQLException e) { } } } } }
 

핵심 키워드

  • JDBC를 이용해서 데이터베이스로부터 데이터를 읽어오기 위해서는 executeQuery ( ) 메소드를 호출해야 한다. executeQuery ( ) 메소드는 가져온 데이터를 ResultSet에 저장하고 리턴한다.
    • ResultSet rs = pstmt.executeQuery();
  • ResultSet의 특징은 커서가 있는 행의 데이터만 읽을 수 있다는 것이다. 커서는 행을 가리키는 포인터를 말한다. ResultSet은 실제 가져온 데이터 행의 앞과 뒤에 beforeFirst 행과 afterLast 행이 붙는데, 최초 커서는 beforeFirst를 가리킨다. 따라서 첫 번째 데이터 행인 first 행을 읽으려면 커서를 이동시켜야 한다. 이때 next() 메소드를 사용한다.
    • boolean result = rs.next();
    • next() 메소드는 커서를 다음 행으로 이동시키는데, 이동한 행에 데이터가 있으면 true를, 없으 면 false를 리턴한다.
    • 만약 SELECT 문으로 가져온 데이터 행이 없다면 beforeFirst 행과 afterLast 행이 붙어 있기 때문 에 첫 번째 next() 결과는 false가 된다.
  • SELECT 문에 따라 ResultSet에는 많은 데이터 행이 저장될 수 있기 때문에 ResultSet을 더 이상 사용하지 않는다면 close() 메소드를 호출해서 ResultSet이 사용한 메모리를 해제하는 것이 좋다.
    • rs.close();
  • 커서가 있는 데이터 행에서 각 컬럼의 값은 Getter 메소드로 읽을 수 있다. 컬럼의 데이터 타입에 따라서 getXxx() 메소드가 사용되며, 매개값으로 컬럼의 이름 또는 컬럼 순번을 줄 수 있다.
    • // 컬럼 이름으로 읽기 String userId = rs.getString("userid"); String userName = rs.getString("username"); int userAge = rs.getInt("userage"); // 컬럼 순번으로 읽기 String userId = rs.getString(1); String userName = rs.getString(2); int userAge = rs.getInt(3);
 

TransactionExam.java

package ch20; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class TransactionExam { public static void main(String[] args) throws Exception { Connection conn = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // 드라이버를 찾아주면 메모리에 스태틱 블록으로 올라간다. // ip, 포트, db명으로 db에 연결 / 계정 / 패스워드 conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/thisisjava", "java", "1234"); System.out.println("연결 성공"); // 트랜잭션 시작 try { conn.setAutoCommit(false); String withdraw = "update accounts set balance=balance-? where ano=?"; String deposit = "update accounts set balance=balance+? where ano=?"; // 1단계 PreparedStatement pstmt = conn.prepareStatement(withdraw); pstmt.setInt(1, 10000); pstmt.setString(2, "111-111-1111"); int rows = pstmt.executeUpdate(); if(rows==0) throw new WithdrawException("출금이 되지 않음"); pstmt.close(); // 2단계 pstmt = conn.prepareStatement(deposit); pstmt.setInt(1, 10000); pstmt.setString(2, "222-222-2222"); rows = pstmt.executeUpdate(); if(rows==0) throw new DepositException("입금이 되지 않음"); pstmt.close(); conn.commit(); System.out.println("계좌 이체가 성공했습니다"); }catch(WithdrawException e) { conn.rollback(); // 에러 발생 시 커넥션을 롤백함 System.out.println(e.getMessage()); }catch(DepositException e) { conn.rollback(); System.out.println(e.getMessage()); }finally { conn.setAutoCommit(true); // 트랜잭션 한 단위가 끝나면 다시 돌려놓아야 한다 } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) { try { // 연결 끊기 conn.close(); System.out.println("연결 끊기"); } catch (SQLException e) { } } } } }
 

핵심 키워드

  • 트랜잭션은 기능 처리의 최소 단위를 말한다. 하나의 기능은 여러 가지 소작업들로 구성될 수 있다. 최소 단위란 것은 이 소작업들을 분리할 수 없으며, 전체를 하나로 본다는 개념이다. 트랜잭션은 소작업들이 모두 성공하거나 모두 실패해야 한다.
  • DB는 트랜잭션을 처리하기 위해 커밋commit과 롤백rollback을 제공한다. 커밋은 내부 작업을 모두 성 공 처리하고, 롤백은 실행 전으로 돌아간다는 의미에서 모두 실패 처리한다.
  • JDBC에서는 INSERT, UPDATE, DELETE 문을 실행할 때마다 자동 커밋이 일어난다. 이 기능은 계좌 이체와 같이 두 가지 UPDATE 문을 실행할 때 문제가 된다. 출금 작업이 성공되면 바로 커밋 이 되기 때문에 입금 작업의 성공 여부와 상관없이 출금 작업만 별도 처리된다.
  • 따라서 JDBC에서 트랜잭션을 코드로 제어하려면 자동 커밋 기능을 꺼야 한다. 자동 커밋 설정 여부 는 Connection의 setAutoCommit() 메소드로 할 수 있다.
    • conn.setAutoCommit(false);
  • 자동 커밋 기능이 꺼지면, 다음과 같은 코드로 커밋과 롤백을 제어할 수 있다.
    • conn.commit(); //커밋하기 conn.rollback(); //롤백하기
  • 트랜잭션을 위한 일반적인 코드 작성 패턴은 다음과 같다.
    • Connection conn = null; try { //트랜잭션 시작 ---------------------------------------------------- //자동 커밋 기능 끄기 conn.setAutoCommit(false); //소작업 처리 … //소작업 처리 … //커밋 -> 모두 성공 처리 conn.commit(); //트랜잭션 종료 ---------------------------------------------------- } catch (Exception e) { try { //롤백 -> 모두 실패 처리 conn.rollback(); } catch (SQLException e1) {} } finally { if(conn != null) { try { //원래대로 자동 커밋 기능 켜기 conn.setAutoCommit(true); //연결 끊기 conn.close(); } catch (SQLException e) {} } }
 

Board.java

package ch20.sec11; import java.util.Date; import lombok.Data; @Data public class Board { private int bno; private String btitle; private String bcontent; private String bwriter; private Date bdate; }

BoardExample.java

package ch20.sec11; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Scanner; public class BoardExample { // 필드 private Scanner scan = new Scanner(System.in); private Connection conn; // 생성자 public BoardExample() { try { // JDBC 드라이버 등록 Class.forName("com.mysql.cj.jdbc.Driver"); // 연결하기 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/thisisjava", "java", "1234"); } catch (Exception e) { e.printStackTrace(); exit(); } } // 메소드 public void list() { // 타이틀 및 컬럼명 출력 System.out.println(); System.out.println("[게시물 목록]"); System.out.println("-------------------------------------------------------"); System.out.printf("%-6s%-12s%-16s%-40s\n", "no", "writer", "date", "title"); System.out.println("-------------------------------------------------------"); // boards 테이블에서 게시물 정보를 가져와서 출력하기 try { String sql = """ select bno, btitle, bcontent, bwriter, bdate from boards order by bno desc; """; PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Board board = new Board(); board.setBno(rs.getInt("bno")); board.setBtitle(rs.getString("btitle")); board.setBcontent(rs.getString("bcontent")); board.setBwriter(rs.getString("bwriter")); board.setBdate(rs.getDate("bdate")); System.out.printf("%-6s%-12s%-16s%-40s \n", board.getBno(), board.getBwriter(), board.getBdate(), board.getBtitle()); } rs.close(); pstmt.close(); } catch (SQLException e) { e.printStackTrace(); exit(); } mainMenu(); } public void mainMenu() { System.out.println(); System.out.println("-------------------------------------------------------"); System.out.println("메인 메뉴: 1.Create | 2.Read | 3.Clear | 4.Exit"); System.out.print("메뉴 선택: "); String menuNo = scan.nextLine(); System.out.println(); switch (menuNo) { case "1" -> create(); case "2" -> read(); case "3" -> clear(); case "4" -> exit(); } } public static void main(String[] args) { BoardExample boardExample = new BoardExample(); boardExample.list(); } public void create() { // 입력 받기 Board board = new Board(); System.out.println("[새 게시물 입력]"); System.out.print("제목: "); board.setBtitle(scan.nextLine()); System.out.print("내용: "); board.setBcontent(scan.nextLine()); System.out.print("작성자: "); board.setBwriter(scan.nextLine()); // 보조 메뉴 출력 System.out.println("-------------------------------------------------------"); System.out.println("보조 메뉴: 1.Ok | 2.Canclel"); System.out.println("메뉴 선택: "); String menuNo = scan.nextLine(); if (menuNo.equals("1")) { // boards 테이블에 게시물 정보 저장 try { String sql = """ insert into boards (btitle, bcontent, bwriter, bdate) values (?, ?, ?, now()); """; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, board.getBtitle()); pstmt.setString(2, board.getBcontent()); pstmt.setString(3, board.getBwriter()); pstmt.executeUpdate(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); exit(); } } // 게시물 목록 출력 list(); } public void read() { // 입력 받기 System.out.println("[게시물 읽기]"); System.out.println("bno: "); int bno = Integer.parseInt(scan.nextLine()); // boards 테이블에서 해당 게시물을 가져와 출력 try { String sql = """ select bno, btitle, bcontent, bwriter, bdate from boards where bno=?; """; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, bno); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { Board board = new Board(); board.setBno(rs.getInt("bno")); board.setBtitle(rs.getString("btitle")); board.setBcontent(rs.getString("bcontent")); board.setBwriter(rs.getString("bwriter")); board.setBdate(rs.getDate("bdate")); System.out.println("#############"); System.out.println("번호: " + board.getBno()); System.out.println("제목: " + board.getBtitle()); System.out.println("내용: " + board.getBcontent()); System.out.println("작성자: " + board.getBwriter()); System.out.println("날짜: " + board.getBdate()); System.out.println("#############"); // 보조 메뉴 출력 System.out.println("----------------------"); System.out.println("보조 메뉴: 1.Update | 2.Delete | 3.List"); System.out.println("메뉴 선택: "); String menuNo = scan.nextLine(); System.out.println(); if (menuNo.equals("1")) { update(board); } else if (menuNo.equals("2")) { delete(board); } } rs.close(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); exit(); } // 게시물 목록 출력 list(); } public void update(Board board) { // 수정 내용 입력 받기 System.out.println("[수정 내용 입력]"); System.out.print("제목: "); board.setBtitle(scan.nextLine()); System.out.print("내용: "); board.setBcontent(scan.nextLine()); System.out.print("작성자: "); board.setBwriter(scan.nextLine()); // 보조 메뉴 출력 System.out.println("------------------------------------------------------"); System.out.println("보조 메뉴: 1.Ok | 2.Cancel"); System.out.print("메뉴 선택: "); String menuNo = scan.nextLine(); if (menuNo.equals("1")) { // boards 테이블에서 게시물 정보 수정 try { String sql = """ update boards set btitle=?, bcontent=?, bwriter=? where bno=? """; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, board.getBtitle()); pstmt.setString(2, board.getBcontent()); pstmt.setString(3, board.getBwriter()); pstmt.setInt(4, board.getBno()); pstmt.executeUpdate(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); exit(); } } // 게시물 목록 출력 list(); } public void delete(Board board) { // boards 테이블에 게시물 정보 삭제 try { String sql = "delete from boards where bno=?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, board.getBno()); pstmt.executeUpdate(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); exit(); } // 게시물 목록 출력 list(); } public void clear() { System.out.println("[게시물 전체 삭제]"); System.out.println("-------------------------------------------------------"); System.out.println("보조 메뉴: 1.Ok | 2.Cancel"); System.out.print("메뉴 선택: "); String menuNo = scan.nextLine(); if (menuNo.equals("1")) { // boards 테이블에 게시물 정보 전체 삭제 try { String sql = "truncate table boards"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.executeUpdate(); pstmt.close(); } catch (Exception e) { e.printStackTrace(); exit(); } } // 게시물 목록 출력 list(); } public void exit() { if(conn != null) { try { conn.close(); }catch(SQLException e) { } } System.out.println("** 게시판 종료 **"); System.exit(0); } }
 

결론!

해당 문제를 풀면서 자바에서의 데이터베이스 입출력을 이해할 수 있었다. 또한 이해한 내용을 바탕으로 직접 데이터베이스에 접근해서 데이터를 추가, 읽기, 수정, 삭제할 수 있는 게시판 어플리케이션을 제작해볼 수 있었다.
Share article

More articles

See more posts

👨🏻‍💻DriedPollack's Blog