package jdbc.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionProvider {
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(
"jdbc:apache:commons:dbcp:guestbook"); // 변경가능
}
}
- Service 클래스 : 사용자의 요청을 처리하는 기능을 제공한다. 기능을 제공하기 위한 로직을 구현하며 DAO 클래스를 이용해서 DB 연동을 처리한다. 가입 신청 처리, 글 목록 제공 등의 기능을 구현한다.
- DAO 클래스 : DB와 관련된 쿼리를 실행한다. Service 클래스들은 데이터를 DB에서 읽어오거나 DB에 데이터를 저장할 때 DAO 클래스를 사용한다.
- JSP(뷰) : Service 클래스가 실행한 결과를 화면에 출력하거나 Service가 기능을 수행하는데 필요한 데이터를 전달한다.
- MVC 프레임워크 : 사용자의 요청을 Service에 전달하고 Service의 실행 결과를 JSP와 같은 뷰에 전달한다. 스프링 MVC프레임와 같은 프레임워크가 MVC 프레임워크에 해당한다.
1.0 데이터 접근 객체 (Data Access Object)의 구현
데이터에 접근할 때 사용하는 객체를 위한 클래스를 의미한다. 일반적으로 한 개의 DB 테이블마다 한 개의 DAO 클래스를 작성한다. 각 DAO 클래스는 INSERT, SELECT, UPDATE, DELETE쿼리를 실행해주는 메서드를 제공한다.
- insert()
- select()
- update()
- delete()
insert() 메서드나 update() 메서드는 자바 객체로부터 값을 읽어와 쿼리를 실행한다.
아래 코드는 DAO 클래스의 insert() 메서드를 작성한 예이다.
public int insert(Connection conn, Message message) throws SQLException {
PreparedStatement pstmt = null;
try {
pstmt = conn.prepareStatement(
"insert into guestbook_message " +
"(guest_name, password, message) values (?, ?, ?)");
pstmt.setString(1, message.getGuestName());
pstmt.setString(2, message.getPassword());
pstmt.setString(3, message.getMessage());
return pstmt.executeUpdate();
} finally {
JdbcUtil.close(pstmt);
}
}
select()
public Message select(Connection conn, int messageId) throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = conn.prepareStatement(
"select * from guestbook_message where message_id = ?");
pstmt.setInt(1, messageId);
rs = pstmt.executeQuery();
if (rs.next()) {
return makeMessageFromResultSet(rs);
} else {
return null;
}
} finally {
JdbcUtil.close(rs);
JdbcUtil.close(pstmt);
}
}
1.1 DAO에서 Connection에 접근하는 방식
DAO가 쿼리를 실행하려면 Statement나 PreparedStatment가 필요한데 이 두 객체는 Connection 객체로부터 구할 수 있따. DAO클래스는 Connction 객체에 접근할 수 있어야 하는데 Connection객체를 구하는 방법은 다음과 같은 세가지 방식이 있다.
- DAO 클래스의 메서드에서 직접 Connection을 생성
- DAO 객체를 생성할 때 생성자로 Connection을 전달받기
- DAO 클래스의 메서드 파라미터로 Connection을 전달받기
DAO 클래스의 메서드에서 직접 Connection을 생성하는 방식
public Message selectById(int messageId) throws SQLException {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(jdbcUrl, userId, userPassword);
...
}finally {
...
if(conn != null) try {conn.close();} catch(SQLException ex) {}
}
}
}
위와 같이 작성한 DAO 클래스를 사용할 때에는 다음처럼 DAO 객체를 생성하고 메서드를 호출하게 된다.
MessageDao dao = ...// MessageDao 객체 구함
Message message = dao.selectById(messageId); //커넥션 생성
message.increseReadCount();
dao.updateReadCount(messageId, message.getReadCount()); //커넥션 생성
DAO 메서드에서 Connection을 직접 생성하는 방식의 단점은 메서드를 실행할 때마다 매번 Connection을 생성한다는 점이다 하나의 기능을 실행할 때 두 개의 Dao 메서드를 호출한다. 각 DAO 메서드에서 Connection을 생성하므로 위 코드는 두개의 Connection 객체를 생성하게 되다. 이는 각 메서드가 서로 다른 Connection 객체를 사용한다는 것을 의미한다. 이 경우 두 메서드를 하나의 드랜잭션으로 처리할 수 없게 된다. JDBC 기반의 트랜잭션은 한 개의 Connection객체에서만 유효하기 때문이다.
- DAO 클래스의 메서드에서 직접 Connection을 생성
- DAO 객체를 생성할 때 생성자로 Connection을 전달받기
- DAO 클래스의 메서드 파라미터로 Connection을 전달받기
public class MessageDao {
private Connection conn;
public MessageDao(Connection conn) {
this. conn = conn;
}
public Message selectById(int messageId) throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = conn.prepareStatement(query, userId, password);
...
}finally {
...
}
}
}
DAO 클래스를 사용하는 코드는 다음과 같이 DAO 객체를 생성할 때 Connection을 전달한 뒤 필요한 메서드를 사용하면 된다.
Connection conn = null;
try {
conn = ... //커넥션을 구함
MessageDao dao = new MessageDao(conn);
Message message = dao.selectById(messageId);
message.increseReadCount();
dao.updateReadcount(messageId, message.getReadCount());
}finally{
if (conn != null) try { conn.close();} catch(SQLException ex) {}
}
DAO 객체의 각 메서드는 하나의 Connection을 사용하기 때문에 JDBC 트랜잭션을 이용할 수 있다. 하지만 매번 새로운 DAO 객체를 생성한다는 단점이 있다.
- DAO 클래스의 메서드에서 직접 Connection을 생성
- DAO 객체를 생성할 때 생성자로 Connection을 전달받기
- DAO 클래스의 메서드 파라미터로 Connection을 전달받기
DAO 메서드를 실행할 때 Connection 을 전달하는 방식이다.
public class MessageDao {
public Message selectById(Connection conn, int messageId) throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = conn.prepareStatement(query, userId, password);
...
}finally {
...
}
}
}
DAO 클래스를 사용하는 코드는 다음과 같이 DAO 메서드를 실행할 때 Connection 객체를 전달해 준다.
Connection conn = null;
try {
conn = ... //커넥션을 구함
MessageDao dao = ... //DAO 객체 구함
Message message = dao.selectById(conn, messageId);
message.increseReadCount(conn);
dao.updateReadcount(conn, messageId, message.getReadCount());
}finally{
if (conn != null) try { conn.close();} catch(SQLException ex) {}
}
두 번째 방식과 마찬가지로 한 개의 Connection 객체를 사용하므로 JDBC 트랜잭션을 사용할 수 있으며 DAO 객체를 매번 생성하지 않아도 되다는 장점이 있다. 다만 DAO 객체의 메서드를 실행할 때마다 Connection 객체를 파라미터로 전달해야 하므로 첫 번째나 두 번째 방식과 비교하면 메서드 호출 코드가 다소 길어진다는 단점이 있다, 또한 실수로 한 트랜잭션으로 실행해야 할 메서드에 다른 Connection을 전달할 수도 있다.
1.2 간단한 close() 및 rollback() 처리 코드를 위한 JdbcUtil
Connection, Statement, ResultSet과 같은 클래스는 사용이 끝나면 close() 메서드를 호출해서 자원을 반환해야한다.
그래서 익셉션 발생 여부에 상과없이 close할 수 있다록 finally 블록에서 close() 메서드를 구현할 수 있다록 한다.
try {
...
}finally {
if(rs != null ) try {rs.close();} catch(SQLException ex){}
if(pstmt != null ) try {pstmt.close();} catch(SQLException ex){}
if(conn != null ) try {conn.close();} catch(SQLException ex){}
}
매번 같은 코드를 작성하는 것은 성가시므로 close() 처리 코드를 줄이기 위해 보조클래스를 작성을 한다.
이클립스 동적 웹 프로젝트를 작성하고 코드를 추가하자.
package jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcUtil {
public static void close(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
}
}
}
public static void close(Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException ex) {
}
}
}
public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
}
}
}
public static void rollback(Connection conn) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
}
}
}
}
Connection 제공하는 ConnectionProvider 만들기
'개발' 카테고리의 다른 글
[JSP] 회원제 게시판 구현 1 : 회원 관련 기능 (0) | 2020.07.27 |
---|---|
[JSP] 방명록 구현 (0) | 2020.07.27 |
[JSP] 커넥션 풀 (0) | 2020.07.26 |
[JSP] 데이터 삽입 / 조회 /정렬 / 집합 / 수정 / 삭제 / 조인 (0) | 2020.07.26 |
[JSP] SQL 기초 - 테이블 생성, 주요 타입 (0) | 2020.07.26 |