JDBC와 DAO, DTO

HY·2022년 3월 31일
0

Java 웹 개발

목록 보기
2/6

본격적으로 Servlet, JSP 등 웹 개발에 들어가기에 앞서, Java에서 어떤 방식으로 DB와 연결할 수 있는지 알아보자.

🔗 JDBC (Java Database Connectivity)

Java에서 데이터베이스에 접속할 수 있도록 하는 Java API
SQL문을 실행할 수 있게 해주는 함수 호출 인터페이스이다. (DB에서 자료를 쿼리하거나 업데이트하는 방법을 제공한다.)
MyBatis, JPA 등도 내부적으로는 모두 JDBC를 사용하고 있다.

DBMS가 달라지더라도 동일한 API를 사용하게 해준다 (Driver와 URL만 수정하면 된다 - Driver는 각 DBMS와 통신을 담당하는 자바 클래스로 JDBC를 사용하기 위해서는 사용하려는 DBMS에 맞는 jar파일이 필요하다)

🔍 Driver

package explorer에서 JDBC를 사용하려는 프로젝트를 마우스 오른쪽 클릭 후 properties를 선택하면 아래와 같은 창이 나온다. 여기서, 왼쪽에서 Java Build Path를 누르고 Libraries에서 Add External JARs를 누른 뒤, 사용하려는 DBMS의 Driver를 선택해주면 된다.

기능

  • 데이터베이스에 연결 설정 (Connection)
  • SQL 문장을 DBMS에 전송 (Statement)
  • SQL 문장 전송 후 결과 처리 (ResultSet)

🔍 예제


db에 위와 같은 book 테이블을 만들고 데이터를 하나 넣어놨다.
JDBC를 사용해서 book 테이블에서 select를 통해 isbn이 '111'인 데이터를 가져오자.

package test;

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

public class JdbcTest {
	
	private final static String URL = "jdbc:mysql://127.0.0.1:3306/(db이름)";
	private final static String USER_ID = "(dbuser)";
	private final static String USER_PWD = "(dbpwd)";
	
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			
			// DB 연결
			conn = DriverManager.getConnection(URL, USER_ID, USER_PWD);
			System.out.println("DB Connection Success!!!!!");
			
			// Query 문 작성
			String sql = "select * from book where isbn = ?";
			
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, "111");
			
			// Query 실행
			rs = pstmt.executeQuery();
			if (rs.next()) {
				System.out.print(rs.getString("isbn") + "\t");
				System.out.print(rs.getString("title") + "\t");
				System.out.print(rs.getString("author") + "\t");
				System.out.print(rs.getInt("price") + "\t");
				System.out.print(rs.getString("desc") + "\t");
				System.out.print(rs.getString("img") + "\t");
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

실행 결과, 아래와 같은 결과가 출력된다.

Connection

DBMS와 연결을 위한 객체

Connection conn = DriverManager.getConnection();

PreparedStatement

✅ SQL 실행을 위한 객체

PreparedStatement pstmt = conn.prepareStatement(sql);

✅ SQL 실행을 위한 메서드

  • Select 처리 시 사용
public ResultSet executeQuery(String sql) throws SQLException
  • DML (delete, update, insert) 수행 시 사용
public int executeUpdate(String sql) throws SQLException

Statement vs PreparedStatement
PreparedStatement는 쿼리에 인자를 부여할 수 있다.(인자 - ?로 사용, pstmt.setString(paramIndex, value) 방식으로 지정 가능)
일반적으로 PreparedStatement를 많이 쓴다.

ResultSet

executeQuery 실행 시 반환되는 객체. 쿼리 실행 결과가 담겨있다.


오버헤드 때문에 작업이 끝나면 반드시 닫아주어야한다. (close)
닫을 때는 finally 부분에서 연결한 순서의 역순으로 닫는다.

📤 DTO와 DAO

DB에서 데이터를 쉽게 가져오고 빼내기 위해 DTO와 DAO를 쓴다
쉽게 얘기하자면, DTO는 DB에서 가져온 데이터를 저장하는 객체를 의미하고 DAO는 DB에 접근해서 데이터를 처리 (CRUD 등)를 위한 객체이다.
DAO에 메서드로 select, insert, delete, update 와 같이 DB에 접근해 데이터를 조작하는 연산을 구현해놓고, 넣어야하거나 빼내야하는 데이터를 DTO를 사용해서 가져오고 빼낸다. 각각에 대해 예제와 함께 좀 더 자세히 알아보자.

🔍 DTO (Data transfer object)

  • 로직을 갖고 있지 않는 순수한 데이터 객체이며, getter/setter 메서드만을 갖는다.
  • 계층 간 데이터 교환을 위한 객체

위의 book 클래스의 데이터를 가져오기 위해 DTO를 만들면 다음과 같다.

package test;

public class BookDto {

	private String isbn;
	private String title;
	private String author;
	private int price;
	private String desc;
	private String img;
	
	public String getIsbn() {
		return isbn;
	}
	public void setIsbn(String isbn) {
		this.isbn = isbn;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public String getDesc() {
		return desc;
	}
	public void setDesc(String desc) {
		this.desc = desc;
	}
	public String getImg() {
		return img;
	}
	public void setImg(String img) {
		this.img = img;
	}
	
}

단순히 테이블에서 가져온 데이터를 저장하기 위해 테이블의 column을 dto 클래스의 attribute로 만들어주고 getter, setter를 만들었다.

🔍 DAO (Data Access Object)

  • 말 그대로 데이터에 접근하는 객체
  • 데이터베이스에 접근해 데이터를 조회하거나 조작하는 기능을 전담하는 객체

Dao를 만들기 전, DB 연결과 닫기를 편리하게 하기 위해 DBUtil 클래스를 생성했다.

package test;

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

public class DBUtil {

	private final String URL = "jdbc:mysql://127.0.0.1:3306/(db이름)";
	private final String USER_ID = "(dbuser)";
	private final String USER_PWD = "(dbpwd)";

	private static DBUtil instance;

	private DBUtil() {
	}

	public static DBUtil getInstance() {
		if (instance == null)
			instance = new DBUtil();
		return instance;
	}

	public Connection getConnection() throws SQLException {
		return DriverManager.getConnection(URL, USER_ID, USER_PWD);
	}

	public void close(AutoCloseable... autoCloseables) {
		try {
			for(AutoCloseable ac : autoCloseables) {
				if(ac != null)
					ac.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

select와 insert 기능이 필요하기 때문에 아래와 같은 인터페이스를 먼저 만들었다.

package test;

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

public interface BookDao {
	
	int insert(BookDto BookDto) throws SQLException;
	List<BookDto> select() throws SQLException;
	
}

아래는 bookDao 인터페이스를 구현한 클래스이다.
여러번 사용되어도 계속 생성해야할 필요가 없기 때문에 singleton으로 구현했다.

package test;

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

public class BookDaoImpl implements BookDao {
	
	private DBUtil dbUtil = DBUtil.getInstance();
	private static BookDao bookDao = new BookDaoImpl();
	
	private BookDaoImpl() {}
	
	public static BookDao getBookDao() {
		return bookDao;
	}

	@Override
	public int insert(BookDto bookDto) throws SQLException {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int ret = 0;
		
		try {
			conn = dbUtil.getConnection();
			String sql = "insert into book values (?, ?, ?, ?, ?, ?)";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, bookDto.getIsbn());
			pstmt.setString(2, bookDto.getTitle());
			pstmt.setString(3, bookDto.getAuthor());
			pstmt.setInt(4, bookDto.getPrice());
			pstmt.setString(5, bookDto.getDesc());
			pstmt.setString(6, bookDto.getImg());
			
			ret = pstmt.executeUpdate();
		} finally {
			dbUtil.close(pstmt, conn);
		}
		return ret;
	}

	@Override
	public List<BookDto> select() throws SQLException {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		List<BookDto> list = new ArrayList<>();
		
		try {
			conn = dbUtil.getConnection();
			String sql = "select * from book";
			pstmt = conn.prepareStatement(sql);
            
			rs = pstmt.executeQuery();
			while (rs.next()) {
				BookDto bookDto = new BookDto();
				bookDto.setIsbn(rs.getString("isbn"));
				bookDto.setTitle(rs.getString("title"));
				bookDto.setAuthor(rs.getString("author"));
				bookDto.setPrice(rs.getInt("price"));
				bookDto.setDesc(rs.getString("desc"));
				bookDto.setImg(rs.getString("img"));
				list.add(bookDto);
			}
			
		} finally {
			dbUtil.close(rs, pstmt, conn);
		}
		return list;
	}

}

0개의 댓글