2022-02-11 JDBC-3

GGAE99·2022년 2월 11일
0

진도

목록 보기
22/43

오늘도 JDBC에 대한 내용을 다뤄본다.
어제 했던 회원관리 프로그램을 더 다듬어서 표현해보겠다. 이전 포스팅을 보고오면 코드가 상당이 긴 것을 확인할 수 있다. try / catch 가 엄청 많이 사용됐기도 하고, 또 모든 값을 하나하나 넣어주려그러니 쓸데없이 코드만 길어진다. 이걸 보완하면서 코드를 한번 짜보도록 해보겠다.
클래스를 이용해서 하나하나 정리해보자.

JDBC 클래스

이번에는 클래스를 더 여러개를 만들어서 정리하며 사용해본다.
사용할 클래스들과 클래스의 역할을 정리하자면

  • JDBCTemplate : db관련 공통코드 처리역할
  • MemberController : 화면담당 / 사용자의 요청을 받는 역할 / 결과처리
  • MemberService : 트랜잭션처리 / 데이터 편집
  • MemberDao : db와 데이터를 주고받는 역할
  • Member : 회원 1명정보를 저장하기위한 데이터의 형태(Value Object -> vo)
  • Start : 프로젝트를 실행

각 클래스를살펴보면서 어떤 역할을 하는지 자세하게 알아보자.

들어가기 전에 정해놓을게 있다.

Connection conn
PreparedStatement pstmt
ResultSet rset

필자가 지금부터 사용하는 모든 코드는 위의 선언을 따른다.

JDBCTemplate

이 클래스는 db관련 코드들을 짜놓는 역할을 한다.
Connection은 db와 연결해주고 값을 주고받게 도와주는 역할을한다. 그런데 연결하는 모든 메소드마다 Connection객체를 생성해준다면 메모리의 낭비가 심해지게된다.
그래서 public static (static method) 를 이용해준다.

static method
static 메소드를 이용하면 프로그램을 시작하는 순간에 java가 딱 한번 메모리를 할당하며 어떤 패키지에서든 불러서 사용할 수 있게된다. 그래서 자주 사용하는 db와 연결하는 객체를 static method로 선언한 것 이다.

이렇게 따로 만들어주는 이유는 또 있다. 사실은 메모리보다 이게 훨씬 중요하다.

JDBCTemplate을 사용하는 이유

  • 우리가 하나의 메소드를 사용할때마다 하나의 쿼리만을 사용하는 것이 아니다.
    3개의 쿼리를 하나의 메소드에서 사용한다고 가정해보자.
    그 3개의 쿼리 중 하나의 쿼리만 틀렸다고 가정하고, 모든 쿼리에 Connection 객체를 따로 만들었다고 생각하면, 틀린 하나의 쿼리를 제외한 2개의 쿼리는 아주 잘 실행되서 결과값이 commit된다.
    그러한 상황을 막아주기 위해서 JDBCTemplate을 만들어주고 모든 쿼리를 끝내고 사이좋게 한꺼번에 commit 또는 rollback을 해주는 것 이다. 동기 버리고 갈 수 없다.

static method로 선언해줄 메소드들은 Connection / commit / rollback / close 이다.

Connection

public static Connection getConnection() {
		Connection conn = null;
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe","jdbc","1234");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return conn;
	}

원래는 db와 연결해줄때마다 Connection 객체를 생성해야했는데, 그걸 한번만 할 수 있도록 만들어줬다. 이제 Connection 객체를 생성하는 것 대신에

Connection conn = JDBCTemplate.getConnection();

을 선언하면 된다.

commit

public static void commit(Connection conn) {
		try {
			//매개변수로 받은 conn이 정상인지 체크
			if(conn != null && !conn.isClosed()) {				
				conn.commit();
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}//commit end

데이터를 성공적으로 변환했을 때 commit을 해서 db에도 데이터를 승인했다고 알려주면서 저장해야하는데 그걸 해주는게 이 commit이다.

JDBCTemplate.commit(conn);

이렇게 사용해주면 된다.

rollback

public static void rollback(Connection conn) {
		try {
			if(conn != null && !conn.isClosed()) {				
				conn.rollback();				
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}//rollback end

rollback은 데이터의 변환에 실패했을때, 값을 가장 최근에 commit한 값으로 돌려주는 기능이다.
메소드에 선언한 쿼리 중 하나라도 틀리면 모두 같이 rollback하기위해 선언했다.

JDBCTemplate.rollback(conn);

사용법이다.

close

public static void close('자원' '?') {
		try {
			//매개변수로 받은 conn이 정상인지 체크
			if('?' != null && !'?'.isClosed()) {				
				'?'.close();
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}//close end
    '?' == conn / pstmt / rset 
    '자원' == Connection / PreparedStatement / ResultSet

close는 코드가 3개다. 3개의 코드 모드 '자원' 부분과 '?'만 다르다.
자원을 사용하고 다 사용하면 컴퓨터한테 자원을 반납해야하지 않겠는가? 그래서 사용한다.

DBCTemplate.close(conn);
DBCTemplate.close(pstmt);
DBCTemplate.close(rset);

사용법이다.
이렇게 JDBCTemplate을 마치겠다.

MemberController

MemberController는 화면담당 / 사용자의 요청을 받는 역할 / 결과처리 만 수행하고 나머지 과정들은 모두 service클래스에 맡긴다. 그래서 사용하는 변수가 Scanner와 service밖에 없다.

private Scanner sc;
	private MemberService service;	
	
	public MemberController() {
		super();
		sc = new Scanner(System.in);
		service = new MemberService();
		
	}

변수는 위와같이 선언한다.

MemberService

MemberService는 트랜잭션 처리와 데이터의 편집을 담당한다.
이 클래스의 진행 순서를 정리해보자.

  1. Connection 생성하기
  2. 현재 변수값을 편집해야하는지?
  3. dao를통한 db작업 (dao가 필됴한 conn및 데이터를 매개변수로 처리)
  4. commit,rollback 여부
  5. 자원 반환
  6. 결과 리턴

MemberController 클래스에서 해야할 일들을 받아오고, db와 직접적으로 통신할 수 있도록 자료를 정리해서 MemberDao클래스에 보내준다. 이 클래스에서 commti과 close가 끝난다.

MemberDao

MemberDao는 db와 데이터를 직접적으로 주고받는 클래스이다. MemberService에서 사용할 자료를 다 정리해서 보내주면 MemberDao클래스가 db와 자료를 주고받고, 결과값을 리턴해준다.
이 과정에서 데이터를 집어넣기 때문에 여기서 Member객체를 넣는 메소드를 만든다.

이 클래스의 진행 순서를 정리하고 코드를 보자.

  1. 필요한 변수 선언
  2. PreparedStatement 객체 생성 (+query문 문법검사)
  3. query에 있는 위치홀더(?)에 값 대체 // 위치홀더가 없으면 이 돠정을 생략한다.
  4. 쿼리문 수행 -> 조호결과 저장
  5. 사용한 자원 반환
public Member getMember(ResultSet rset) {
		Member m = new Member();
		try {
			m.setAddress(rset.getString("address"));
			m.setAge(rset.getInt("age"));
			m.setEmail(rset.getString("email"));
			m.setEnrollDate(rset.getDate("enroll_date"));
			m.setGender(rset.getString("gender"));
			m.setMemberId(rset.getString("member_id"));
			m.setMemberName(rset.getString("member_name"));
			m.setMemberNo(rset.getInt("member_no"));
			m.setMemberPw(rset.getString("member_pw"));
			m.setPhone(rset.getString("phone"));
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return m;
	}//getMember end

이제 Member객체에 데이터를 집어넣을 때

Member m = getMember(rset);

를 하면 된다.

이 클래스에서 PreparedStatement와 ResultSet을 사용하고 모두 반환해준다.

PreparedStatement pstmt = null;
ResultSet rset = null;
finally {
	JDBCTemplate.close(rset);
	JDBCTemplate.close(pstmt);
}

아까 JDBCTemplate에서 만들어줬던 close매소드를 사용하면된다.

Member

Member클래스는 데이터베이스에서 선언한 테이블의 변수와 같은 변수를 넣어주면 된다. 같은 형을 사용하도록 주의하자! 여기서 Getter Setter도 만들고, 생성자도 만든다.

Start

public class Start {
	public static void main(String[] args) {
		MemberController mc = new MemberController();
		mc.main();		
	}
	
}

그냥 여태 짰던 코드 실행해주는 코드이다.

물론 클래스의 이름을 달리해도 괜찮다. 그냥 의미만 알아듣게 잘 설정하자.
JDBC를 더 깔끔하게 정리하는 방법을 알아보았다.
여기까지!

0개의 댓글