JDBC/JDBC 수업

#26. JDBC, Connection, Statement, ResultSet

열하나요 2023. 8. 7. 14:55

26-1. 요약

JDBC를 이용하여 MVC모델을 구현할 수 있다.

 

M (model)

- VO(Value Object)

VO(Value Object) => 값을 담는 역할
  => DB테이블의 한 행에 대한 데이터를 기록할 수 있는 저장용 객체
   
  유사
  DTO(Data Transfer Object)
  DO(Domain Object)
  Entity
  bean
   
  VO 조건
  1. 반드시 캡슐화를 적용
  2. 모든 필드에 대한 getter/setter 메서드를 작성할 것
  3. 기본생성자(필수!) 및 매개변수 생성자를 작성할 것

 

 

- DAO(Data Access Object)

JDBC용 객체
  - Connection : DB의 연결정보를 담고 있는 객체
  - (Prepared)Statement : 해당 DB에 SQL문을 전달하고 실행한 후 결과를 받아내는 객체
  - ResultSet : 만약에 실행한 SQL문이 SELECT문일 경우 조회된 결과들이 담겨있는 객체
  ** Statement의 특징 : 완성된 SQL문을 실행할 수 있는 객체
   
JDBC 처리 순서
  1) JDBC Driver 등록 : 해당 DBMS가 제공하는 클래스 등록
  2) Connection 객체 생성 : 접속하고자하는 DB정보를 입력해서 접속하면서 반환
  3) Statement 객체 생성 : Connection객체를 이용해서 생성
  4) SQL문을 전달하면서 실행 : Statement객체를 이용해서 SQL문을 실행
   > SELECT문일 경우 - executeQuery() 호출
   > DML문일 경우 - executeUpdate() 호출
  5) 결과 받기
   > SELECT문일 경우 -> ResultSet객체(조회된 데이터들이 담김)로 받기 => 6_1
   > DML문일 경우 -> int(처리된 행 수)로 받기   => 6_2
  6_1) ReseultSet에 담겨있는 데이터들을 하나하나씩 뽑아서 VO객체에 담기
  6_2) 트랜잭션 처리(성공이면 COMMIT, 실패면 ROLLBACK)
  7) 사용이 끝난 JDBC용 객체들을 반드시 자원반납(close()) => 생성된 순서의 역순으로
  8) 결과반환(Controller)
   > SELECT문일 경우 -> 6_1) 만들어진 결과(VO)
   > DML문일 경우 -> int(처리된 행 수)

 

V (view) 

View : 사용자가 보게 될 시각적인 요소(화면 입/출력)

 

C (controller)

Controller : View를 통해서 온 요청을 처리하는 담당
해당 메소드로 전달된 데이터를 가공처리한 후 DAO메소드를 호출
DAO로부터 반환받은 결과에 따라서 사용자가 보게 될 View(응답화면)을 결정(View메소드를 호출)

 

26-2. 실습

실전!!!!

사용자에게 입력을 받아 출력해주자.

View로 사용자에게 먼저 입력받고 Controller를 호출하면,

Controller는 요청을 처리하고 DAO에게 요청을 보냄

DAO는 받은 요청을 DB로 전송하고 다시 요청한 곳으로 retrun..

Controller도 return..

View에서만 출력값(System.out.println())!

 

1. oracle (DBMS) 에 테이블을 만든다.

------------------------------------ SQL 스크립트 ------------------------------------

DROP TABLE MEMBER;
CREATE TABLE MEMBER(
    USERNO NUMBER PRIMARY KEY,
    USERID VARCHAR2(15) UNIQUE NOT NULL,
    USERPWD VARCHAR2(20) NOT NULL,
    USERNAME VARCHAR2(15) NOT NULL,
    GENDER CHAR(1) CHECK(GENDER IN('M', 'F')),
    AGE NUMBER,
    EMAIL VARCHAR(30),
    PHONE CHAR(11),
    ADDRESS VARCHAR2(100),
    HOBBY VARCHAR2(50),
    ENROLLDATE DATE DEFAULT SYSDATE NOT NULL
);

DROP SEQUENCE SEQ_USERNO;
CREATE SEQUENCE SEQ_USERNO
NOCACHE;

INSERT INTO MEMBER
VALUES (SEQ_USERNO.NEXTVAL, 'admin', '1234', '관리자', 'M', 50, 'admin@kh.or.kr', '01011112222', '서울시 마포구', '잠자기', '2023/07/31');

INSERT INTO MEMBER
VALUES (SEQ_USERNO.NEXTVAL, 'user01', 'pass01', '홍길동', 'M', 15, 'hong@gmail.com', '01022223333', '한양', NULL, SYSDATE);

COMMIT;


SELECT * FROM MEMBER;

여기서 중요한 건, COMMIT

 

2. VO 생성

------------------------------------ Member 클래스 ------------------------------------

public class Member {
	
	private int userNo; //USERNO	NUMBER
	private String userId; //USERID	VARCHAR2(15 BYTE)
	private String userPwd; //USERPWD	VARCHAR2(20 BYTE)
	private String userName; //USERNAME	VARCHAR2(15 BYTE)
	private String gender; //GENDER	CHAR(1 BYTE)
	private int age; //AGE	NUMBER
	private String email; //EMAIL	VARCHAR2(30 BYTE)
	private String phone; //PHONE	CHAR(11 BYTE)
	private String address; //ADDRESS	VARCHAR2(100 BYTE)
	private String hobby; //HOBBY	VARCHAR2(50 BYTE)
	private Date enrollDate; //ENROLLDATE	DATE
    
    public Member(String userId, String userPwd, String userName, String gender, int age, String email, String phone,
        String address, String hobby) {
    super();
    this.userId = userId;
    this.userPwd = userPwd;
    this.userName = userName;
    this.gender = gender;
    this.age = age;
    this.email = email;
    this.phone = phone;
    this.address = address;
    this.hobby = hobby;
    }
}

필드, 생성자, gettet/setter 등을 만든다. (몇가지 생략)

여기서 중요한 건, 생성자를 만들 때, SEQUENCE와 DEFAULT등의 조건으로 값이 들어가는 경우 해당 필드를 뺀 생성자를 추가할 것!!

 

<테이블에 행 추가하기>

3. View에서 사용자에게 입력받기 

테이블의 행에 추가할 값들을 입력받아 넘겨준다.

------------------------------------ MemberView 클래스 ------------------------------------

public class MemberView {
	private Scanner sc = new Scanner(System.in);
	private MemberController mc = new MemberController();
    
    private void insertMember() {
    	mc.insertMember(userId, userPwd, userName, gender, age, email, phone, address, hobby);
	}
}

 

4. 호출된 Controller에서 요청 처리

------------------------------------ MemberController 클래스 ------------------------------------

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

    Member m = new Member(userId, userPwd, userName, gender, age, email, phone, address, hobby);
    int result = new MemberDao().insertMember(m);
}

객체의 값을 매개변수로 받고, DAO에게 매개변수로 넘겨주기

 

☆☆☆☆☆☆☆☆☆☆☆☆☆☆여기가 이번 수업의 핵심이다!!!!!!!!!!!!!!!!!☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

5. DAO에서 DB와 연결해서 INSERT

------------------------------------ MemberDao 클래스 ------------------------------------

public class MemberDao {
	
	public int insertMember(Member m) {
		
		int result = 0; // 처리된 결과 (행의 개수)를 담아줄 변수
		Connection conn = null; // 접속한 DB의 연결정보를 담는 변수
		Statement stmt = null; // SQL문 실행 후 결과를 받기 위한 변수
        
		String sql = "INSERT "
                            + "INTO "
                            + 		"MEMBER "
                            + "VALUES (SEQ_USERNO.NEXTVAL, "
                            + "'" + m.getUserId()   + "', "
                            + "'" + m.getUserPwd()  + "', "
                            + "'" + m.getUserName() + "', "
                            + "'" + m.getGender()   + "', "
                                  + m.getAge()		+ " , "
                            + "'" + m.getEmail() 	+ "', "
                            + "'" + m.getPhone() 	+ "', "
                            + "'" + m.getAddress() 	+ "', "
                            + "'" + m.getHobby()	+ "', "
                            + "SYSDATE)";
		
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC");
			stmt = conn.createStatement();
			result = stmt.executeUpdate(sql);
			
			if(result > 0) { // 성공했을 경우
				conn.commit();
			} else { // 실패했을 경우
				conn.rollback();
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				stmt.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return result; // 처리된 행의 수
	}
}

1) 필요한 변수 선언 (String sql에 값을 담을 때는 SQL문에 INSERT INTO와 동일한 문법으로 담아준다.)

2) 필요한 객체 생성 (Connection, Statement 등)

3) 결과받고 트랜잭션

4) 자원반납 (생성 역순으로)

5) 결과반환

 

6. Controller에서 결과를 반환받은 것을 View에게 넘겨주기

------------------------------------ Controller 클래스 ------------------------------------

    if(result > 0) { // 성공했을 때
                new MemberView().displaySuccess();
            } else { // 실패했을 때
                new MemberView().displayFail();
            }

 MemberView()를 필드에 만들면 안됨 (중첩복제.....)

 

7. View에서 사용자에게 화면 출력!

	public void displaySuccess() {
		System.out.println("\n서비스 요청 성공!!");
	}
	
	public void displayFail() {
		System.out.println("\n서비스 요청 실패 ㅠㅠ..");
	}

 

<테이블 조회하기>

3'. View에서 사용자에게 입력받기 

------------------------------------ MemberView 클래스 ------------------------------------

public void selectAll() {
		System.out.println("--- 회원 전체 조회 ---");
		mc.selectAll();
	}

4'. 호출된 Controller에서 요청 처리

------------------------------------ MemberController 클래스 ------------------------------------

public void selectAll() {
    List<Member> list = new MemberDao().selectAll();
}

반환이 list<Member>이므로 list<Member>로 받아준다.

 

5'. DAO에서 DB와 연결해서 SELECT

------------------------------------ MemberDao 클래스 ------------------------------------

public List<Member> selectAll() {

    Connection conn = null; // 접속된 DB연결정보를 담을 객체
    Statement stmt = null; // SQL문 실행 후 결과를 받기 위한 객체
    ResultSet rset = null; // SELECT문을 수행하고 조회 결과값들이 처음 담길 객체

    String sql = "SELECT "
                        + "USERNO, "
                        + "USERID, "
                        + "USERPWD, "
                        + "USERNAME, "
                        + "GENDER, "
                        + "AGE, "
                        + "EMAIL, "
                        + "PHONE, "
                        + "ADDRESS, "
                        + "HOBBY, "
                        + "ENROLLDATE "
                + "FROM " 
                        + "MEMBER";

    List<Member> list = new ArrayList(); 

    try {
        // 1) JDBC Driver 등록
        Class.forName("oracle.jdbc.driver.OracleDriver");

        // 2) Connection 객체 생성
        conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC");

        // 3) Statement 객체 생성
        stmt = conn.createStatement();

        // 4, 5) SQL문(SELECT문)을 전달해서 실행 후 결과(ResultSet)받기
        rset = stmt.executeQuery(sql);

        // 6_1) 현재 조회 결과가 담긴 ResultSet에서 한 행씩 뽑아서 VO객체에 담기
        // rset.next()
        // 커서를 한 줄 아래로 옮겨주고 해당 행이 존재할 경우 true / 아니면 false 반환
        while(rset.next()) {
            // 현재 rset의 커서가 가리키고 있는 해당 행의 데이터를
            // 하나씩 뽑아서 Member객체의 필드에 값을 대입
            Member m = new Member();

            m.setUserNo(rset.getInt("USERNO"));
            m.setUserId(rset.getString("USERID"));
            m.setUserPwd(rset.getString("USERPWD"));
            m.setUserName(rset.getString("USERNAME"));
            m.setGender(rset.getString("GENDER"));
            m.setAge(rset.getInt("AGE"));
            m.setEmail(rset.getString("EMAIL"));
            m.setPhone(rset.getString("PHONE"));
            m.setAddress(rset.getString("ADDRESS"));
            m.setHobby(rset.getString("HOBBY"));
            m.setEnrollDate(rset.getDate("ENROLLDATE"));
            
            // List에 해당 Member객체를 요소로 추가하기!
            list.add(m);
        }

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {
            rset.close();
            stmt.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    return list;
}

rset으로부터 어떤 컬럼에 해당하는 값을 뽑을건지 명시
rset.getInt(컬럼명 또는 컬럼순번) : int형 값을 뽑아낼 때
rset.getString(컬럼명 또는 컬럼순번) : String형 값을 뽑아낼 때
rset.getDate(컬럼명 또는 컬럼순번) : Date형 값을 뽑아낼 때
            => 컬럼명(대소문자를 가리지 않음)
            => 권장사항 : 컬럼명으로 적고 대문자를 쓰는 것을 권장

 

6'. Controller에서 결과를 반환받은 것을 View에게 넘겨주기

------------------------------------ Controller 클래스 ------------------------------------

	if(list.isEmpty()) { 
			new MemberView().displayNoDate();
		} else { 
			new MemberView().displayList(list);
		}

list를 만약 null;값으로  초기화한다면 isEmpty()를 사용할 수 없다(nullPointException)

 

끝.

'JDBC > JDBC 수업' 카테고리의 다른 글

#31. JDBC(Properties)  (0) 2023.08.14
#30. JDBC(model에 service클래스 추가), Template  (0) 2023.08.11
#29. test... 팀플과제  (0) 2023.08.10
#28. PreparedStatement  (0) 2023.08.09
#27. JDBC, Connection, Statement, ResultSet  (0) 2023.08.08