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