국비/JDBC

[01] JDBC (MVC패턴, DAO, Connection, Statement)

박머루 2022. 5. 10. 21:39
MVC 패턴
 * Model : 데이터와 관련된 역할 (데이터를 담는다거나, DB에 접근해서 데이터 입출력)
 * View : 사용자가 보게 될 시각적인 요소 / 화면(입력, 출력)
 * Controller : 사용자의 요청을 받아서 처리 후 응답화면을 지정하는 역할

 * View단에서만 출력문(System.out.println)을 사용한다.
 * Model의 DAO(Data Access Object)에서만 DB에 직접적으로 접근한 후 해당 SQL문 실행 및 결과를 받는다.
ojdbc6.jar
 *  프로젝트 선택 후 마우스 우클릭 -> Properties -> JavaBuildPath -> Libraries ->
 *  Add External JARs... -> c:\dev\ojdbc6.jar 선택 -> Apply -> Apply and Close
    
 *  References Libraries에 ojdbc6 추가 확인
     -> 안해놓으면 ClassNotFoundException 발생함
Statement란?
해당 DB에 SQL문을 전달하고 실행한 후 결과를 받아주는 객체
완성된 SQL문을 실행할 수 있는 객체
Connection 클래스의 createStatement() 호출하여 생성
excuteXXX 호출시 SQL문을 매개변수로 전달하여 질의 수행
DAO(Data Access Object)
 * 데이터베이스 관련된 작업(CRUD)을 전문적으로 담당하는 객체
 * DAO 안에 모든 메소드를 데이터베이스와 관련된 작업으로 만든다

 * CRUD - CREATE, RETRIEVE(READ), UPDATE, DELETE(DESTORY)

 * SQL DML
 *       SELECT
 
 * Controller를 통해서 호출된 기능을 수행
 * DB에 직접적으로 접근한 후 해당 SQL문을 실행 및 결과 받기(JDBC)
    * JDBC용 객체
   - Connection : DB의 연결정보를 담고 있는 객체
   - (Prepared) Statement : 해당 DB에 SQL문을 전달하고 실행한 후 결과를 받아내는 객체
     //prepared statement -> statement의 자식클래스, 더 진화된?
   - ResultSet : 만일 실행한 SQL문이 SELECT문일 경우 조회된 결과들이 담겨있는 객체
  * JDBC 처리 순서 !!! 중요 !!!

1) JDBC Driver 등록 : 해당 DBMS가 제공하는 클래스 등록

2) Connection 객체 생성 : 접속하고자하는 DB정보를 입력해서 DB에 접속하면서 생성
   
3) Statement 객체 생성 : Connection 객체를 이용해서 생성
    
4) SQL문을 전달하면서 실행 : Statement 객체를 이용해서 SQL문 실행
    > SELECT문일 경우 - executeQuery(); 호출
    > DML문일 경우 - executeUpdate(); 호출
     
5) 결과 받기
    > SELECT문일 경우 - ResultSet 객체 이용(조회된 데이터들이 담겨있음) => 6_1
    > DML문일 경우 - int(처리된 행의 수)로 받기 => 6_2 
     
 6_1) SELECT문일 경우 -  ResultSet에 담겨있는 데이터들을 하나하나씩 뽑아서 VO객체에 담기
 6_2) DML문일 경우 - 트랜잭션 처리 (성공이면 COMMIT, 실패하면 ROLLBACK)
    
 7) 다 쓴 JDBC용 객체들 자원반납(close()) => 생성된 역순으로
    
 8) 결과반환 (Controller)
    > SELECT문일 경우 - 6_1) 만들어진 결과 ResultSet
    > DML문일 경우 - int(처리된 행 수)


Member - VO클래스
VO(Value Object)
- Member 테이블의 컬럼들과 유사하게 필드 구성
- sequence와 default 등의 조건으로 값이 들어가는 경우에는 해당 필드를 뺀 생성자를 추가해준다.
public class Member {
	
	// 필드는 DB 컬럼정보와 유사하게 작업!
    private int userNo; // USERNO NUMBER PRIMARY KEY,
    private String userId; // USERID VARCHAR2(15) UNIQUE NOT NULL,
    private String userPwd; // USERPWD VARCHAR2(20) NOT NULL,
    private String userName; // USERNAME VARCHAR2(20) NOT NULL,
    private String gender; // GENDER CHAR(1) CHECK(GENDER IN('M','F')),
    private int age; // AGE NUMBER,
    private String email; // EMAIL VARCHAR2(30),
    private String phone; //PHONE CHAR(11),
    private String address; // ADDRESS VARCHAR2(100),
    private String hobby; // HOBBY VARCHAR2(50),
    private Date enrollDate; // ENROLLDATE DATE DEFAULT SYSDATE NOT NULL // DATE -- import java.sql
    
    
    
    // 기본생성자
    public Member() {}
    
    
    // 매개변수를 모두 받는 생성자
	public Member(int userNo, String userId, String userPwd, String userName, String gender, int age, String email,
			String phone, String address, String hobby, Date enrollDate) {
		super();
		this.userNo = userNo;
		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;
		this.enrollDate = enrollDate;
	}
	
	// 회원추가용 생성자(default등 조건으로 들어가는 값 제외)
	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;
	}
	

	public int getUserNo() {
		return userNo;
	}
	public void setUserNo(int userNo) {
		this.userNo = userNo;
	}
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getUserPwd() {
		return userPwd;
	}
	public void setUserPwd(String userPwd) {
		this.userPwd = userPwd;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getHobby() {
		return hobby;
	}
	public void setHobby(String hobby) {
		this.hobby = hobby;
	}
	public Date getEnrollDate() {
		return enrollDate;
	}
	public void setEnrollDate(Date enrollDate) {
		this.enrollDate = enrollDate;
	}

	
	
	@Override
	public String toString() {
		return "Member [userNo=" + userNo + ", userId=" + userId + ", userPwd=" + userPwd + ", userName=" + userName
				+ ", gender=" + gender + ", age=" + age + ", email=" + email + ", phone=" + phone + ", address="
				+ address + ", hobby=" + hobby + ", enrollDate=" + enrollDate + "]";
	} 
}

회원 정보를 추가해보자!!
MemberView - View 클래스
사용자가 보게 될 시각적인 요소(화면) (입력 및 출력)
/**
	 * 회원 추가용 화면
	 * 추가하고자하는 회원의 정보를 입력받아서 추가 요청할 수 있는 화면
	 */
	public void insertMember() { //insertMember
		System.out.println("-----회원 추가-----");
		System.out.print("아이디 > ");
		String userId = sc.nextLine();
		System.out.print("비밀번호 > ");
		String userPwd = sc.nextLine();
		System.out.print("이름 > ");
		String userName = sc.nextLine();
		System.out.print("성별 >");
		String gender = sc.nextLine().toUpperCase(); // 대문자로 변경
		System.out.print("나이 > ");
		int age = sc.nextInt();
		sc.nextLine();
		System.out.print("이메일 > ");
		String email = sc.nextLine();
		System.out.print("전화번호 > ");
		String phone = sc.nextLine();
		System.out.print("주소 > ");
		String address = sc.nextLine();
		System.out.print("취미(, 로 공백없이 나열) > ");
		String hobby = sc.nextLine();
		
		// 회원 추가 요청 => Controller의 어떤 메소드 호출
		mc.insertMember(userId, userPwd, userName, gender, age, email, phone,
						address, hobby);
		
	} // insertMember
Controller
view를 통해서 요청 기능을 처리
해당 메소드로 전달된 데이터를 가공 처리한 후 Dao메소드 호출
Dao로부터 반환받은 결과에 따라 사용자가 보게 될 View(응답화면)을 결정 (View메소드 호출)
view에서 사용자에게 입력받은 정보를 받아와 Member 객체에 담아 Dao클래스로 보내 실행 결과를 int형으로 반환받는다.
int형 반환값 결과에 따라 성공했을 경우, 실패했을 경우를 조건문으로 나누어 View클래스에 String형 결과를 보내준다
/**
	 * 사용자의 회원 추가 요청을 처리해주는 메소드
	 * @param userId
	 * @param userPwd
	 * @param userName
	 * @param gender
	 * @param age
	 * @param email
	 * @param phone
	 * @param address
	 * @param hobby
	 * => 사용자가 요청 시 입력했던 값들
	 */
	public void insertMember(String userId, String userPwd, String userName, String gender, int age, 
							 String email, String phone, String address, String hobby) {
		
		// 전달된 데이터들을 Member객체에 담기 (회원추가용생성자)
		Member m = new Member(userId, userPwd, userName, gender, age, email, phone, address, hobby);
		
		int result = new MemberDao().insertMember(m); // dao에서 int형으로 결과값 반환되어 옴
		
		if(result > 0) { // 성공했을 경우
			new MemberView().displaySuccess("회원 가입 성공");
		} else { // 실패했을 경우
			new MemberView().displayFail("회원 가입 실패");
		}
		
	} // insertMember
DAO클래스
데이터베이스 관련된 작업(CRUD)을 전문적으로 담당하는 객체
DAO 안에 모든 메소드를 데이터베이스와 관련된 작업으로 만든다
Controller 클래스에서 Member형 객체를 받아왔다.
Member객체에 접근하여(.getXXX) 정보를 가져와 INSERT문을 완성시켜 DB에 값을 넣어주도록 하자.

DB에 접근하기 위해서는 Class.forName()메소드를 이용하여 JDBC Driver를 등록해준다.
Driver를 등록하면 DriverManager 클래스를 사용할 수 있게 되며 .getConnection()메소드를 사용해서
Connection 객체를 생성하여 DB와 연결해준다.

Connection객체의 createStatement() 메소드를 사용하여 Statement 객체를 생성한다.

우리가 작성해놓은 INSERT문은 DML문이므로 Statement 객체의 executeUpdate()메소드를 사용한다.
메소드에 완성된 SQL문을 넣어 DB에전달하고 실행 결과를 int형 값으로 반환받는다.

DML 구문 실행 후에는 트랜잭션 처리를 해줘야 하는데,
반환받은 int형 결과 값을 이용해 조건문을 작성하여 실행에 성공했을 경우에는 commit, 실패했을 경우에는 rollback 처리를 하도록 해준다.

다 쓴 JDBC용 객체 자원 반납을 해준다. 생성된 역순으로.close()

마지막으로 int형 결과를 Controller클래스의 insertMember 메소드에 반환해준다.
	public int insertMember(Member m) { // insertMember
		// INSERT => int 처리된 행 수 => 트랜잭션처리
		
		// 필요한 변수들 먼저 세팅
		int result = 0; // 처리된 결과(행 수)를 담아줄 변수
		Connection conn = null; // 접속된 DB의 연결정보를 담는 변수
		Statement stmt = null; // SQL문 실행 후 결과를 받기 위한 변수
		
		// 실행할 SQL문(완성된 형태로 만들어줘야 함)
//		INSERT INTO MEMBER
//		VALUES (SEQ_USERNO.NEXTVAL, 'XXXX', 'XXXX', 'XXXX', 'XXXX', 'XX', 'X', SYSDATE);
		
		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)";
		
		// System.out.println(sql); 잘 출력되는지 확인
		
		
		try { // 1) JDBC Driver 등록!
			Class.forName("oracle.jdbc.driver.OracleDriver");
			// ojdbc6.jar가 누락되었거나, 잘 추가되었지만 오타가 있을 경우
			// => ClassNotFoundException 발생!
			
			//2) Connection 객체 생성(db와 연결 -> url, 계정명, 비번)
//			DriverManager.getConnection(url, 계정명, 비밀번호)
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe"
												,"JDBC"
												,"JDBC");
			
			// 3) Statement객체 생성
			stmt = conn.createStatement();
			
			// 4, 5) DB에 완성된 SQL문을 전달하면서 실행 후 결과
			result = stmt.executeUpdate(sql);
			
			
			// 6_2) dml 구문 트랜잭션처리
			
			if(result > 0) { // 성공했을 경우
				conn.commit();
			} else { // 실패했을 경우
				conn.rollback();
			}
			
			
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try { // 7) 다 쓴 JDBC용 객체 자원 반납 => 생성된 역순으로 close()
				stmt.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		// 8) 결과 반환. 성공했는지 실패했는지?
		return result; // 처리된 행의 수
	} // insertMember
view 클래스
DAO에서 반환한 int result 값을 Controller에서 받아 성공했을 경우 "회원 가입 성공 ", 실패했을 경우 "회원 가입 실패" 라는 String형 값을 view 클래스의 displaySuccess메소드와 displayFail 메소드로 반환받았다.
이 값을 서비스 요청 처리 후 사용자가 볼 수 있도록 출력해준다.
	// 서비스 요청 처리 후 사용자가 보게 될 응답화면
	
	public void displaySuccess(String message) {
		System.out.println("\n서비스 요청 성공!! :"+  message);
	}
	
	public void displayFail(String message) {
		System.out.println("\n서비스 요청 실패!" + message);
	}