클라우드 융합 Full-stack 웹 개발자 양성과정/SQL, JDBC

SQL응용 - JDBC(Template, Service)

thesunset 2022. 10. 12. 23:21

1. Template

<JDBCTemplate>

com.kh.common

: JDBC 과정 중 반복적으로 쓰이는 구문들을 각각의 메소드로 정의해둘 곳

=>  "재사용할 목적"으로 공통 템플릿 작업 진행

이 클래스에서 모든 메소드들은 전부 다 static메소드를 만들 것(객체 생성 X)

* 싱글톤패턴 : 메모리영역에 단 한 번만 올라간 것을 재사용한 개념

< 공통적인 부분 뽑아내기 >

1) DB와 접속된 Connection객체를 생성해서 반환시켜주는 메소드

public static Connection getConnection() {

    //Connection객체를 담을 그릇 생성
    Connection conn = null;

    try {
        //1,2) 연결시키기
        Class.forName("oracle.jdbc.driver.OracleDriver");

        conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC");
        conn.setAutoCommit(false);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }

    return conn;
}

2)  전달받은 Connection객체를 가지고 트랜잭션 처리를 해주는 메소드 

2-1) 전달받은 Connection객체를 가지고 COMMIT시켜주는 메소드 

public static void commit(Connection conn) {
    try {
        if(conn != null && !conn.isClosed()) {//conn이 null이 아니고 닫혀있지 않을 때 
        conn.commit();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

2-2) 전달받은 Connection가지고 ROLLBACK시켜주는 메소드

public static void rollback(Connection conn) {
    try {
        if(conn != null && !conn.isClosed()) {
        conn.rollback();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

3. 전달받은 JDBC용 객체를 반납시켜주는 메소드(각 객체별로) 

3-1) Connection객체를 전달받아서 반납시켜주는 메소드 

public static void close(Connection conn) {
    try {
        if(conn != null && !conn.isClosed()) {
        conn.close();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

3-2) Statement객체 전달받아서 반납시켜주는 메소드(오버로딩)

=> 다형성으로 인해 PrepardeStatement객체 또한 매개변수로 전달이 가능 (부모자식관계)

public static void close(Statement stmt) {
    try {
        if(stmt != null && !stmt.isClosed()) {
        stmt.close();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

3-3) ResultSet객체를 전달받아서 반납시켜주는 메소드(오버로딩 적용)

public static void close(ResultSet rset) {
    try {
        if(rset != null && !rset.isClosed()) {
        rset.close();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
}

2. Service

: 기존의 DAO의 역할을 분담

-  Controller에서 Service호출(Connection객체 생성) 후 Service를 거쳐서 DAO로 넘어갈 것
-  DAO호출 시 Connection 객체와 기존에 넘기고자했던 인자값을 같이 넘겨줌 
-  DAO처리가 끝나면 서비스단에서 결과에 따른 트랜잭션처리도 같이 해줌 
   => Service단을 추가하므로써 DAO는 순수하게 SQL문을 처리하는 부분만 남음

< Controller > 

1. View로부터 전달된 데이터를 가공 후 Service의 메소드를 호출해 전달 & 결과값으로 응답화면 지정 

public class MemberController {

public void insertMember(String userId, String userPwd, String userName, 
                        String gender, int age, String email, String phone, 
                        String address, String hobby) { 

    //1. 전달된 데이터들을 Member 객체에 담기 => 가공처리
    Member m = new Member(userId, userPwd, userName, gender, age, email, phone, address, hobby);

    //2. Service의 insertMember()호출  
    int result = new MemberService().insertMember(m);

    //3. 결과값에 따라서 사용자가 보게 될 응답화면 지정
    if(result > 0) {
        new MemberView().displaySuccess("회원 추가 성공");
    }else {
        new MemberView().displayFail("회원 추가 실패");
    }
}

< Service > 

1. Connection 객체 생성

public class MemberService {
	public int insertMember(Member m) {
		
		//Connection 객체 생성
		Connection conn = getConnection();

2. DAO로 생성한 conn과 controller로부터 받았던 값 전달하기

//DAO호출 시 Connection객체와 기존에 넘기려 했던 Member를 함께 넘김
int result = new MemberDao().insertMember(conn, m);

3. DML의 경우 트랜잭션처리

//결과에 따른 트랜잭션 처리 
if(result > 0) {
    commit(conn);
} else {
    rollback(conn);
}

4. Connection 객체 반납 & 결과값 Controller로 리턴 

//Connection 객체 반납
close(conn);

return result;
}

< DAO > 

1. Service에서 이미 Connection 객체를 생성했기 때문에 필요한 변수를 셋팅하고 PreparedStatement객체를 생성

+ 자원반납은 이 메소드에서 객체 생성한 자원만 반납하기(conn은 아직 할 일이 남음)

public class MemberDao {

public int insertMember(Connection conn, Member m) {
    //INSERT => 처리된 행의 갯수 => 트랜잭션처리 
    //0) 필요한 변수 먼저 셋팅
    int result = 0; //처리된 결과(행의 갯수)를 담아줄 변수
    PreparedStatement pstmt = null; //SQL문 실행 후 결과를 받기 위한 변수 

    String sql = "INSERT INTO MEMBER VALUES(SEQ_USERNO.NEXTVAL, ?, ?, ?, ?, ?, ?, ?, ?, ?, SYSDATE)";

    //1~2번은 Connection을 생성하며 이미 만들어옴

    try {
        //3_1) PreparedStatement 객체생성(SQL문을 미리 넘겨준다)
        pstmt = conn.prepareStatement(sql);

        //3_2) 미완성된 SQL문일 경우 완성시켜주기
        //pstmt.setXXX(?의 위치, 실제값);

        pstmt.setString(1, m.getUserId());
        pstmt.setString(2, m.getUserPwd());
        pstmt.setString(3, m.getUserName());
        pstmt.setString(4, m.getGender());
        pstmt.setInt(5, m.getAge());
        pstmt.setString(6, m.getEmail());
        pstmt.setString(7, m.getPhone());
        pstmt.setString(8, m.getAddress());
        pstmt.setString(9, m.getHobby());


        //4, 5) DB에 완성된 SQL문을 실행 후 결과(*처리된 행의 갯수) 받기
        result = pstmt.executeUpdate();

    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close(pstmt);
    }
    return result;
}

=> DML의 경우 Service에서 트랜잭션처리와 Connection 반납하기