코딩 화이팅 2023. 3. 16. 13:39

JDBC(Java Data Connectivity)

  • Java 프로그램에서 DB에 일관된 방식으로 접근할 수 있도록 API를 제공하는 클래스의 집합
  • 데이터베이스에서 자료를 쿼리(SELECT)하거나 업데이트하는 방법을 제공
  • Java에서는 JDBC를 이용하여 SQL을 DMBS와 주고받음
  • DBMS의 종류에 관계 없이 사용 가능(약간의 설정만 조금 수정하면 가능)

JDBC 이용하여 DB 연결하는 방법 4단계

  1. JDBC 드라이버 로드
  2. 데이터 베이스 연결
  3. SQL문 실행
  4. 데이터베이스 연결 끊음

JDBC 드라이버 로드

  • DB와 연결하기 위해서는 사용할 JDBC 드라이버를 프로그램 시작할 때 로딩
  • 필요한 DBMS의 jar 파일을 프로젝트에 추가한다.
  • java.lang.Class 클래스의 정적 메소드 forName(클래스 이름)을 이용하여 JVM 안으로 클래스를 메모리에 적재
  • DriverManager를 통해 접근 가능

DB별 Driver Class

  • MySQL : com.mysql.cj.jdbc.Driver
  • Oracle : oracle.jdbc.driver.OracleDriver
  • SQL Server : com.Microsoft.sqlserver.jsdbc.SQLServerDriver
package com.ssafy.Test;


//1. JDBC 드라이버를 로드
//2. 데이터베이스 연결(Connection)
//3. SQL 준비 및 실행
//4. 데이터베이스 연결 해제

public class JDBCtest {
	
	public JDBCtest() {
		//드라이버를 로드한다.
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			System.out.println("드라이버 로딩 성공");
		} catch (ClassNotFoundException e) {			
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		JDBCtest db=new JDBCtest();
	}
}
//
드라이버 로딩 성공

데이터베이스 연결

  • DriverManager 클래스의 static 메소드인 getConnection(URL, UserId, UserPassword)을 통해 연결 요청

DB별 URL

  • MySQL : jdbc:/mysql://HOST:PORT/DATABASE[?키=값&키=값...]
-- SQL
DROP DATABASE IF EXISTS ssafy_board;
CREATE DATABASE ssafy_board DEFAULT CHARACTER SET utf8mb4;

USE ssafy_board;

CREATE TABLE board (
	id INT AUTO_INCREMENT,
    -- id가 1씩 증가
    writer VARCHAR(20) NOT NULL,
    title VARCHAR(50) NOT NULL,
    -- NOT NULL : 비워두면 안됨
    content TEXT,
    -- 비워둬도 됨
    view_cnt INT DEFAULT 0,
    reg_date TIMESTAMP DEFAULT now(),
    PRIMARY KEY(id)
);

INSERT INTO board(title, writer, content) 
VALUES ("BackEnd 너두 마슷허","양씨","너도 할 수 있어"),
	   ("누르지마시오", "따봉맨", "아무내용없음"),
       ("대답잘하는 법", "송소연", "채팅 잘치면됨 네(필쑤)");

SELECT * FROM board;
//Java
package com.ssafy.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.List;

import com.ssafy.board.model.dto.Board;

//1. JDBC 드라이버를 로드
//2. 데이터베이스 연결(Connection)
//3. SQL 준비 및 실행
//4. 데이터베이스 연결 해제

public class JDBCtest {
	
	public JDBCtest() {
		//드라이버를 로드한다.
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			System.out.println("드라이버 로딩 성공");
		} catch (ClassNotFoundException e) {			
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		JDBCtest db=new JDBCtest();
	}
	
	private List<Board>seletAll(){
		List<Board> list=new ArrayList<>();
		
		//2. 데이터 베이스를 연결
		Connection conn=DriverManager.getConnection("jdbc:mysql://localhost::3306/ssafy_boared?serverTimezone=UTC", "ssafy", "ssafy");
		
		
		return list;
	}
}

SQL 실행

  • SQL문을 수행하기 위해서는 Statement 객체가 필요하다.
  • Connection  객체를 이용하여 createStatement() 메소드를 통해 생성한다.
  • exectueQuery(String sql) : SELECT 문과 같이 결과값이 여러 개의 레코드로 구해지는 경우 사용
  • executeUpdate(String sql) : INSERT, UPDATE, DELETE 문과 같이 테이블이 변경만 되고 결과가 없는 경우 사용 반환 값은 int형

ResultSet

  • Query에 대한 결과 값 처리
  • 반환 값이 여러 개인 경우에 이를 받아서 쉽게 처리할 수 있게 설계됨.
  • next()를 통해 현재 행에서 다음 행으로 커서 이동
  • getXXX(column Name/index)를 통해 값을 가져올 수 있음.
package com.ssafy.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import com.ssafy.board.model.dto.Board;

//1. JDBC 드라이버를 로드
//2. 데이터베이스 연결(Connection)
//3. SQL 준비 및 실행
//4. 데이터베이스 연결 해제

public class JDBCtest {
	
	public JDBCtest() {
		//드라이버를 로드한다.
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			System.out.println("드라이버 로딩 성공");
		} catch (ClassNotFoundException e) {			
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		JDBCtest db=new JDBCtest();
		for(Board b:db.seletAll()) {
			System.out.println(b);
		}
	}
	
	private List<Board>seletAll(){
		List<Board> list=new ArrayList<>();
		
		//2. 데이터 베이스를 연결
		try {
			Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC", "ssafy", "ssafy");
			Statement stmt=conn.createStatement();
			//전체 값을 가져오는 SQL문 작성
			String sql="SELECT*FROM board";
			
			ResultSet rs= stmt.executeQuery(sql);
			
			//데이터베이스에서 index는 1부터 시작
			while (rs.next()) {
				Board board=new Board();
				board.setId(rs.getInt("id"));
				board.setTitle(rs.getString("title"));
				board.setWriter(rs.getString("writer"));
				board.setContent(rs.getString("content"));
				board.setRegDate(rs.getString("reg_date"));
				board.setViewCnt(rs.getInt("view_cnt"));
				
				list.add(board);
			}			
			rs.close();
			stmt.close();
			conn.close();
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		return list;
	}
}
//
드라이버 로딩 성공
Board [id=1, title=BackEnd 너두 마슷허, writer=양씨, content=너도 할 수 있어, regDate=2023-03-16 10:08:23, viewCnt=0]
Board [id=2, title=누르지마시오, writer=따봉맨, content=아무내용없음, regDate=2023-03-16 10:08:23, viewCnt=0]
Board [id=3, title=대답잘하는 법, writer=송소연, content=채팅 잘치면됨 네(필쑤), regDate=2023-03-16 10:08:23, viewCnt=0]

PreparedStatement

  • Statement의 단점을 극복한 인터페이스
  • 간단하게 쿼리문을 작성할 수 있도록 도움을 줌
  • Connection 인터페이스의 prepareStatement(String sql) 메서드를 통해 가져옴.
  • executeQuery() / executeUpdate() 사용
  • SQL문은 ?기호를 사용해서 표현 가능 ["INSERT INTO member VALUES(?,?,?,?)";]
  • ?기호에 값을 setXXX(int 순서 / 실제 데이터나 변수)를 통해 할당해야 함.
public void insertBoard(Board board) throws SQLException {
//		String sql="INSERT INTO board (title, writer, content) VALUES("		
		String sql="INSERT INTO board (title, writer, content) VALUES(?,?,?)";
		
		Connection conn=null;
		PreparedStatement pstmt=null;
		
		conn=util.getConnection();
		pstmt=conn.prepareStatement(sql);
		
		pstmt.setString(1, board.getTitle());
		pstmt.setString(2, board.getWriter());
		pstmt.setString(3, board.getContent());
		
		pstmt.executeUpdate();
		
		util.close(pstmt, conn);
	}
    ============================================================
    //try,catch문으로도 구현 가능
    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(pstmt, conn);
		}
		
	}

게시판 만들기(실전)

//Board라는 게시판의 객체 생성
package com.ssafy.board.model.dto;

public class Board {
	private int id;
	private String title;
	private String writer;
	private String content;
	private String regDate;
	private int viewCnt;

	public Board() {
	}

	public Board(String title, String writer, String content) {
		super();
		this.title = title;
		this.writer = writer;
		this.content = content;
	}
	
	

	public Board(int id, String title, String writer, String content, String regDate, int viewCnt) {
		this.id = id;
		this.title = title;
		this.writer = writer;
		this.content = content;
		this.regDate = regDate;
		this.viewCnt = viewCnt;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getWriter() {
		return writer;
	}

	public void setWriter(String writer) {
		this.writer = writer;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getRegDate() {
		return regDate;
	}

	public void setRegDate(String regDate) {
		this.regDate = regDate;
	}

	public int getViewCnt() {
		return viewCnt;
	}

	public void setViewCnt(int viewCnt) {
		this.viewCnt = viewCnt;
	}

	@Override
	public String toString() {
		return "Board [id=" + id + ", title=" + title + ", writer=" + writer + ", content=" + content + ", regDate="
				+ regDate + ", viewCnt=" + viewCnt + "]";
	}

}
/**
 * Mysql DB 연결 객체를 제공하주고, 사용했던 자원을 해제하는 기능을 제공하는 클래스입니다.
 */
package com.ssafy.board.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;


public class DBUtil {
	/**
     * DB 접속에 필요한 url을 작성한다.
     * url은 jdbc:mysql://[host][:port]/[database][?propertyName1][=propertyValue1]형태로 작성한다.
     * serverTimezone=UTC 설정이 없으면 오류가 발생하므로 주의한다.
     */
	// DB와 연결하기위해 필요한 DB의 URL
	private final String url = "jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC";
	// DB의 USER 이름
	private final String username = "ssafy";
	// 위 USER의 PASSWORD
	private final String password = "ssafy";
	// Mysql 드라이버 클래스 이름
	private final String driverName = "com.mysql.cj.jdbc.Driver";

	/**
     * Singleton Design Pattern을 적용해준다.
     */
    private static DBUtil instance = new DBUtil();

    private DBUtil() {
        // JDBC 드라이버를 로딩한다. 드라이버 로딩은 객체 생성 시 한번만 진행하도록 하자.
        try {
            Class.forName(driverName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static DBUtil getInstance() {
        return instance;
    }
    /**
     * DriverManager를 통해 Connection을 생성하고 반환한다.
     *
     * @return
     * @throws SQLException
     */
    public Connection getConnection() throws SQLException{
    	return DriverManager.getConnection(url, username, password);
    }

//	public static void close(Connection conn, PreparedStatement pstmt) {
//		try {
//			if (pstmt != null)
//				pstmt.close();
//		} catch (SQLException e) {
//			e.printStackTrace();
//		}
//
//		try {
//			if (conn != null)
//				conn.close();
//		} catch (SQLException e) {
//			e.printStackTrace();
//		}
//	}
//
//	public static void close(Connection conn, PreparedStatement pstmt, ResultSet rs) {
//		try {
//			if (rs != null)
//				rs.close();
//		} catch (SQLException e) {
//			e.printStackTrace();
//		}
//		
//		try {
//			if (pstmt != null)
//				pstmt.close();
//		} catch (SQLException e) {
//			e.printStackTrace();
//		}
//
//		try {
//			if (conn != null)
//				conn.close();
//		} catch (SQLException e) {
//			e.printStackTrace();
//		}
//	}
	
	/**
     * 사용한 리소스들을 정리한다.
     * Connection, Statement, ResultSet 모두 AutoCloseable 타입이다.
     * ... 을 이용하므로 필요에 따라서
     * select 계열 호출 후는 ResultSet, Statement, Connection
     * dml 호출 후는 Statement, Connection 등 다양한 조합으로 사용할 수 있다.
     *
     * @param closeables
     */
    public void close(AutoCloseable... closeables) {
        for (AutoCloseable c : closeables) {
            if (c != null) {
                try {
                    c.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package com.ssafy.board.model.dao;

import java.sql.SQLException;
import java.util.List;

import com.ssafy.board.model.dto.Board;

public interface BoardDao {
	//전체 게시글을 몽땅 들고 오쎄용
	public List<Board> selectAll();
	
	//ID에 해당하는 게시글 하나 가져오기
	public Board selectOne(int id) throws SQLException;
	
	//게시글 등록
	public void insertBoard(Board board) throws SQLException;
	
	//게시글 삭제 
	public void deleteBoard(int id) throws SQLException;
	
	//게시글 수정
	public void updateBoard(Board board) throws SQLException;
	
	//조회수 증가
	public void updateViewCnt(int id) throws SQLException;
	
}
package com.ssafy.board.model.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import com.ssafy.board.model.dto.Board;
import com.ssafy.board.util.DBUtil;

//싱글턴으로 만들기
public class BoardDaoImpl implements BoardDao{

	//DBUtil 가져와야됨
	private final DBUtil util=DBUtil.getInstance();
	
	private static BoardDaoImpl instance=new BoardDaoImpl();
	private BoardDaoImpl() {		
	}
	
	public static BoardDaoImpl getinstance() {
		return instance;
	}
	
	@Override
	public List<Board> selectAll() {
		
		List<Board> list=new ArrayList<>();
		Connection conn=null;
		Statement stmt=null;
		ResultSet rs=null;
		//2. 데이터 베이스를 연결
		try {
//			conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC", "ssafy", "ssafy");
			conn=util.getConnection();
			//위 아래는 같다.
			
			stmt=conn.createStatement();
			//전체 값을 가져오는 SQL문 작성
			String sql="SELECT*FROM board";
			
			rs= stmt.executeQuery(sql);
			
			//데이터베이스에서 index는 1부터 시작
			while (rs.next()) {
				Board board=new Board();
				board.setId(rs.getInt("id"));
				board.setTitle(rs.getString("title"));
				board.setWriter(rs.getString("writer"));
				board.setContent(rs.getString("content"));
				board.setRegDate(rs.getString("reg_date"));
				board.setViewCnt(rs.getInt("view_cnt"));
				
				list.add(board);
			}				
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			util.close(rs, stmt, conn);
		}
		
		
		return list;
	}

	@Override
	public Board selectOne(int id) throws SQLException {
		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();
			
			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));
		}
		finally {
			util.close(rs, pstmt, conn);
		}
		
		return board;
	}

	@Override
	public void insertBoard(Board board) throws SQLException {
//		String sql="INSERT INTO board (title, writer, content) VALUES("		
		String sql="INSERT INTO board (title, writer, content) VALUES(?,?,?)";
		
		Connection conn=null;
		PreparedStatement pstmt=null;
		
		conn=util.getConnection();
		pstmt=conn.prepareStatement(sql);
		
		pstmt.setString(1, board.getTitle());
		pstmt.setString(2, board.getWriter());
		pstmt.setString(3, board.getContent());
		
		pstmt.executeUpdate();
		
		util.close(pstmt, conn);
	}
	@Override
	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);
		int result=pstmt.executeUpdate();
		System.out.println(result+"개의 데이터가 지웠습니다.");
		}
		finally {
			util.close(pstmt, conn);
		}
	}

	@Override
	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(pstmt, conn);
		}
		
	}

	@Override
	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);
		}
		
	}

}