Programming Language/Javascript, ...

[JDBC] MVC - PreparedStatement

Ma_Sand 2022. 4. 4. 02:51
반응형

PreparedStatement

   : SQL문을 바로 실행하지 않고 잠시 보관한다.

  - 미완성된 SQL문을 먼저 전달하고, 실행하기 전에 완성 형태로 만든 후 실행한다.

  - 미완성된 SQL문 만들기

    → 사용자가 입력한 값들이 들어갈 수 있는 공간을 위치홀더 '?'로 확보한다.

    → 각 위치홀더에 맞는 값을 세팅한다.

  - Statement의 자식 객체이다.

  - Statement와의 차이점

   ① Statement는 완성된 SQL문을 작성하는 반면, PreparedStatement는 미완성된 SQL문에 위치홀더 '?'를

       사용하여 작성한다.

   ② Statement로 작성 시: 'stmt = conn.createStatement();'

       PreparedStatement로 작성 시: 'pstmt = conn.preparedStatement(sql);'

   ③ Statement로 SQL문 실행 시: 'stmt.executeXXX(sql);'

       PreparedStatement로 SQL문 실행 시

         : 'pstmt.setString(?위치, 값);', 'pstmt.setInt(?위치, 값);', '결과 = pstmt.executeXXX();'

  - 한 번만 실행할 땐 Statement를 사용하고, 여러 번 실행할 땐 preparedStatement를 사용하는 것이 좋다.

 

 

 

 

VO

package member.model.vo;

import java.sql.Date;

public class Member {

    private int userNo;
    private String userId;
    private String userPw;
    private String userName;
    private String gender;
    private int age;
    private String email;
    private String phone;
    private String address;
    private String hobby;
    private Date enrollDate;
    
	public Member() {
		super();
	}
	
	public Member(int userNo, String userId, String userPw, String userName, String gender
                , int age, String email, String phone, String address, String hobby
                , Date enrollDate) {
		super();
		this.userNo = userNo;
		this.userId = userId;
		this.userPw = userPw;
		this.userName = userName;
		this.gender = gender;
		this.age = age;
		this.email = email;
		this.phone = phone;
		this.address = address;
		this.hobby = hobby;
		this.enrollDate = enrollDate;
	}
	
	
	// 회원 추가용 생성자(userNo와 enrollDate 제외한 매개변수 생성자)
	public Member(String userId, String userPw, String userName, String gender, int age
                , String email, String phone, String address, String hobby) {
		super();
		this.userId = userId;
		this.userPw = userPw;
		this.userName = userName;
		this.gender = gender;
		this.age = age;
		this.email = email;
		this.phone = phone;
		this.address = address;
		this.hobby = hobby;
	}
	
	public Member(String userId, String userPw, String email, String phone, String address) {
		super();
		this.userId = userId;
		this.userPw = userPw;
		this.email = email;
		this.phone = phone;
		this.address = address;
	}

	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 getUserPw() {
		return userPw;
	}
	public void setUserPw(String userPw) {
		this.userPw = userPw;
	}
	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 + ", userPw=" + userPw
           + ", userName=" + userName + ", gender=" + gender + ", age=" + age + ", email="
           + email + ", phone=" + phone + ", address=" + address + ", hobby=" + hobby
           + ", enrollDate=" + enrollDate + "]";
	}
}

 

 

 

 

Run

package member.run;

import member.view.MemberView;

public class Run {
	public static void main(String[] args) {
		new MemberView().mainMenu();	
	}
}

 

 

 

 

View

package member.view;

import java.util.ArrayList;
import java.util.Scanner;

import member.controller.MemberController;
import member.model.vo.Member;

// View : 사용자가 보게 될 시각적인 요소를 담당한다.
public class MemberView {
	private Scanner sc = new Scanner(System.in);
	
	// 전역으로 MemberController에 요청할 수 있는 객체 생성
	private MemberController mc = new MemberController();

	public void mainMenu() {
		// 프로그램 종료 전까지 메뉴 선택을 반복하기 위해 while문으로 감싸기
		while(true) {
			System.out.println("========회원관리 프로그램=========");
			System.out.println("1. 회원 추가");
			System.out.println("2. 회원 전체 조회");
			System.out.println("3. 회원 아이디로 검색");
			System.out.println("4. 회원 이름 검색");
			System.out.println("5. 회원 정보 변경");
			System.out.println("6. 회원 탈퇴");
			System.out.println("0. 프로그램 종료");
			System.out.println("=================================");
			System.out.println("원하는 메뉴 번호를 입력하세요. ");
			int menu = sc.nextInt();
			sc.nextLine();
			
			switch(menu) {
			case 1: insertMember(); break;
			case 2: selectAll(); break;
			case 3: searchById(); break;
			case 4: searchByName(); break;
			case 5: updateMember(); break;
			case 6: deleteMember(); break;
			case 0: System.out.println("프로그램을 종료합니다."); return;  
                     // break;를 쓰면 스위치문에서만 벗어나고 다시 반복됨
			default: System.out.println("메뉴번호를 잘못 입력하였습니다.");
			}
			
			
		}
	}
 
	// 회원 추가용 화면
	// 추가하고자 하는 회원의 정보를 입력받아 추가 '요청'할 수 있는 화면

	// 1. 회원 추가 화면
	public void insertMember() {
		System.out.println("-------회원 추가-------");
		// 입력
		// 회원번호(시퀀스) enrollDate(default SYSDATE) 두 컬럼에 대해서 입력받지 않는다.
		System.out.println("아이디: ");
		String userId = sc.nextLine();
		System.out.println("비밀번호: ");
		String userPw = sc.nextLine();
		System.out.println("이름: ");
		String userName = sc.nextLine();
		System.out.println("성별: ");
		String gender = sc.nextLine();
		System.out.println("나이: ");
		int age = sc.nextInt();
		sc.nextLine();
		System.out.println("이메일: ");
		String email = sc.nextLine();
		System.out.println("휴대번호: (- 없이 숫자만 입력)");
		String phone = sc.nextLine();
		System.out.println("주소: ");
		String address = sc.nextLine();
		System.out.println("취미: ");
		String hobby = sc.nextLine();
		
		// 입력받은 정보를 매개변수로 넘겨서 회원 추가 요청 - Controller에 있는 메소드를 호출한다
		mc.insertMember(userId, userPw, userName, gender, age, email, phone, address, hobby);
	}
	
	// 2. 회원 전체 조회 화면
	public void selectAll() {
		System.out.println("--------회원 전체 조회--------");
		
		// Controller에 회원 전체 조회 요청
		mc.selectAll();
	}

	// 3. 회원 아이디로 검색하는 화면
	public void searchById() {
		System.out.println("-------회원 아이디로 검색-------");
		System.out.println("검색할 회원의 아이디 입력: ");
		String userId = sc.nextLine();
		
		// 입력한 아이디로 Controller에 요청하기
		mc.searchById(userId);
	}
	
	// 4. 회원 이름으로 검색하는 화면
	public void searchByName() {
		System.out.println("--------회원 이름으로 검색--------");
		System.out.println("검색할 회원의 이름 입력: ");
		String userName = sc.nextLine();
		
		mc.searchByName(userName);
		
	}
	
	// 5. 회원 정보를 수정하는 화면
	public void updateMember() {
		System.out.println("---------회원 정보 변경---------");
		
		// 변경할 회원의 아이디
		System.out.println("변경할 회원의 아이디: ");
		String userId = sc.nextLine();
		
		// 변경할 정보들
		System.out.println("변경할 비밀번호 입력: ");
		String userPw = sc.nextLine();
		System.out.println("변경할 이메일 입력: ");
		String email = sc.nextLine();
		System.out.println("변경할 휴대번호 입력: ");
		String phone = sc.nextLine();
		System.out.println("변경할 주소 입력: ");
		String address = sc.nextLine();
		
		// 회원 정보 수정 요청
		mc.updateMember(userId, userPw, email, phone, address);
	}
	
	// 6. 회원 탈퇴하는 화면
	// 
	public void deleteMember() {
		System.out.println("---------회원 탈퇴---------");
		
		System.out.println("회원 탈퇴할 아이디: ");
		String userId = sc.nextLine();
		
		mc.deleteMember(userId);
	}
	
	//---------------------------------------------------
    
	// 서비스 요청 시 사용자가 보게될 응답 화면
	
	// 서비스 요청 성공 시 응답 화면
	public void displaySuccess(String message) {

		System.out.println("서비스 요청 성공: " + message);
	}

	// 서비스 요청 실패시 응답 화면
	public void displayFail(String message) {
		System.out.println("서비스 요청 실패: " + message);
		
	}


	// 전체 조회 결과가 없을 때 응답 화면
	public void displayNoData(String message) {
		System.out.println(message);
	}

	// 전체 조회 결과가 있을 때 응답 화면
	public void displayList(ArrayList<Member> list) {
		System.out.println("조회된 결과는 " + list.size() + "건입니다.");
		// 향상된 for문
		for(Member m : list) {  // for(반환할타입 변수명 : 반복할저장소(컬렉션/배열))
			System.out.println(m);
		}
	}


	// 조회결과가 하나일 때
	public void displayOne(Member m) {
		System.out.println("조회된 결과는 다음과 같습니다.");
		System.out.println(m);
	}
}

 

 

 

 

Controller

package member.controller;

import java.util.ArrayList;

import member.model.dao.MemberDao;
import member.model.vo.Member;
import member.view.MemberView;


public class MemberController {

	public void insertMember(String userId, String userPw, String userName, String gender
                           , int age, String email, String phone, String address
                           , String hobby) {
		// 1. 전달된 데이터들을 Member 객체에 담기(가공 처리)
		Member m = new Member(userId, userPw, userName, gender, age, email, phone, address
                            , hobby);
		
		// 2. Dao의 insertMember 메소드를 호출(가공된 멤버객체를 보낸다.)
		int result = new MemberDao().insertMember(m);
		
		// 3. Dao에서 작업한 결과값에 따라 View에 보여질 화면을 정해준다.
		if(result > 0) {
			// 성공했으니 성공 메시지를 보낸다.
			new MemberView().displaySuccess("회원 추가 성공");
		} else {
			// 실패했으니 실패 메시지를 보낸다.
			new MemberView().displayFail("회원 추가 실패");
		}
		
	}

	// 사용자의 회원 전체 조회 요청을 처리해주는 메소드
	public void selectAll() {
		// view에서 controller로 전체조회 요청 받음 -> Dao에게 DB로부터 전체조회해오라고 요청함
		// -> Dao가 Controller에게 전체조회한 결과값을 전달해줌
		
		// 결과값을 담을 변수
		// SELECT - ResultSet -> ArrayList<Member>
		ArrayList<Member> list = new MemberDao().selectAll();
		// DAO에서 작업을 끝마친 결과를 전달받아 해당 결과를 토대로 어떤 화면을 보여줄지 정하여 
        // view에 전달한다.
		
		// 조회결과가 있는지 없는지 판단 후 사용자가 보게될 화면을 지정한다.
		if(list.isEmpty()) { // list가 비어있어 true인 경우
			new MemberView().displayNoData("전체 조회 결과가 없습니다.");
		} else {  // list 조회된 경우 list에 Member가 담겨있음
			new MemberView().displayList(list);
		}
	}

	// 사용자가 입력한 아이디로 검색 요청을 처리해주는 메소드
	public void searchById(String userId) {
		Member m = new MemberDao().searchById(userId);
		
		if(m == null) {
			new MemberView().displayNoData(userId+"에 해당하는 조회 결과가 없습니다.");
		} else {
			new MemberView().displayOne(m);
		}
	}


	// 사용자가 입력한 이름으로 검색 요청을 처리해주는 메소드
	public void searchByName(String userName) {
		ArrayList<Member> list = new MemberDao().searchByName(userName);
		
		if(list.isEmpty()) {
			new MemberView().displayNoData(userName+"에 해당하는 조회 결과가 없습니다.");
		} else {
			new MemberView().displayList(list);
		}
	}

	// 사용자가 입력한 정보들을 변경 요청을 처리해주는 메소드
	public void updateMember(String userId, String userPw, String email, String phone
                           , String address) {
		Member m = new Member(userId, userPw, email, phone, address);
		
//		m.getUserId();
//		m.getUserPw();
//		m.getEmail();
//		m.getPhone();
//		m.getAddress();
		
		int result = new MemberDao().updateMember(m);
		
		if(result > 0) {
			new MemberView().displaySuccess("회원 정보 변경 성공");
		} else {
			new MemberView().displayFail("회원 정보 변경 실패");
		}
	}

	// 사용자가 입력한 정보들을 삭제 요청 처리해주는 메소드
	public void deleteMember(String userId) {
		int result = new MemberDao().deleteMember(userId);
		
		if(result > 0) {
			new MemberView().displaySuccess("회원 탈퇴되었습니다.");
		} else {
			new MemberView().displayFail(userId+"에 해당하는 아이디가 없습니다.");
		}
	}	
}

 

 

 

 

DAO

package member.model.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import member.model.vo.Member;

public class MemberDao {
	public int insertMember(Member m) { 
		int result = 0; 
		Connection conn = null;  
		PreparedStatement pstmt = null;  
		
		// INSERT INTO MEMBER VALUES(SEQ_USERNO.NEXTVAL, 'XXX', 'XXX', ... SYSDATE);
		String sql = "INSERT INTO MEMBER VALUES(SEQ_USERNO.NEXTVAL, ?, ?, ?, ?, ?, ?, ?
                                              , ?, ?, DEFAULT)";
		
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC"
                                             , "JDBC");
			pstmt = conn.prepareStatement(sql);
			
			// 미완성된 SQL문 완성시켜주기
			pstmt.setString(1, m.getUserId());
			pstmt.setString(2, m.getUserPw());
			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());
			
			result = pstmt.executeUpdate();
			
			if(result > 0) {  
				conn.commit();
			} else { 
				conn.rollback();
			}
		} catch (ClassNotFoundException | SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				pstmt.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}	
		return result; 
	}
	
	public ArrayList<Member> selectAll(){
		
		Connection conn = null;
		Statement stmt = null;
		ResultSet rset = null;
		
	
		ArrayList<Member> list = new ArrayList<>(); 
		
		// 실행할 SQL문
		String sql = "SELECT * FROM MEMBER";
		
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC"
                                             , "JDBC");
			stmt = conn.createStatement();
			rset = stmt.executeQuery(sql);
			
            /// 커서를 한 줄 옮기고 해당 위치에 데이터가 있으면 true, 없으면 false
			while(rset.next()) {
				// 현재 커서가 가르키고 있는 행의 데이터를 뽑아 Member 객체에 담기
				Member m = new Member();
				/*
				 * rset으로부터 어떤 컬럼에 해당하는 값을 뽑을 건지 제시
				 * -> 컬럼명(대소문자 가리지 않음), 컬럼 순번
				 * -> 권장사항 = 컬럼명 + 대문자
				 * rset.getInt() = int형 값 뽑을 때
				 * rset.getString() = String형 값 뽑을 때
				 * rset.getDate() = Date형 값 뽑을 때
				 * */
				m.setUserNo(rset.getInt("USERNO"));
				m.setUserId(rset.getString("USERID"));
				m.setUserPw(rset.getString("USERPW"));
				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"));
				// 한 행에 대한 모든 컬럼의 데이터값을 Member 객체 필드에 각각 담았다.
				
				list.add(m);
			}
		} catch (ClassNotFoundException | SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				rset.close();
				stmt.close();
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return list;  
        // 행의 데이터를 갖고 있는 Member 객체들이 인덱스에 담겨있는 리스트를 반환한다.
	}
	
	// 사용자에게 입력받은 아이디로 해당 회원이 있는지 정보 검색 처리하는 메소드
	public Member searchById(String userId) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rset = null;
		
		Member m = null;
		
		String sql = "SELECT * FROM MEMBER WHERE USERID = ?";
		
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC"
                                             , "JDBC");
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, userId);
			rset = pstmt.executeQuery();
			
			if(rset.next()) {
				m = new Member(rset.getInt("USERNO")
						     , rset.getString("USERID")
						     , rset.getString("USERPW")
						     , rset.getString("USERNAME")
						     , rset.getString("GENDER")
						     , rset.getInt("AGE")
						     , rset.getString("EMAIL")
						     , rset.getString("PHONE")
						     , rset.getString("ADDRESS")
						     , rset.getString("HOBBY")
						     , rset.getDate("ENROLLDATE"));
			}
		} catch (ClassNotFoundException | SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				rset.close();
				pstmt.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return m;
	}

	public ArrayList<Member> searchByName(String userName) {
		Connection conn = null;
		PreparedStatement pstmt= null;
		ResultSet rset = null;
		
		ArrayList<Member> list = new ArrayList<>();
		
//		String sql = "SELECT * FROM MEMBER WHERE USERNAME LIKE ?";
//		pstmt.setString(1, "%" + userName + "%");  <- 위와 세트

		String sql = "SELECT * FROM MEMBER WHERE USERNAME LIKE '%' || ? || '%'";
		
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC"
                                             , "JDBC");
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, userName);
			rset = pstmt.executeQuery();
			
			while(rset.next()) {
				list.add(new Member(rset.getInt("USERNO")
					              , rset.getString("USERID")
					              , rset.getString("USERPW")
					              , rset.getString("USERNAME")
					              , rset.getString("GENDER")
					              , rset.getInt("AGE")
		             			  , rset.getString("EMAIL")
					              , rset.getString("PHONE")
					              , rset.getString("ADDRESS")
					              , rset.getString("HOBBY")
					              , rset.getDate("ENROLLDATE")));
		 	}
		} catch (ClassNotFoundException | SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				rset.close();
				pstmt.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;
	}

	public int updateMember(Member m) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int result = 0;  // DML은 몇 행 실행되었는지 확인해야 하므로 int형
		
		String sql="UPDATE MEMBER"
                + " SET"
                + "    USERPW=?"
                + ",   EMAIL=?"
                + ",   PHONE=?"
                + ",   ADDRESS=?"
                + "WHERE USERID=?";
		
		try {
            Class.forName("oracle.jdbc.driver.OracleDriver");
            conn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe",
                                                "JDBC","JDBC");
            pstmt=conn.prepareStatement(sql);
            
            pstmt.setString(1,m.getUserPw());
            pstmt.setString(2,m.getEmail());
            pstmt.setString(3, m.getPhone());
            pstmt.setString(4, m.getAddress());
            pstmt.setString(5, m.getUserId());
            
            result=pstmt.executeUpdate();
            
            if(result>0) {
                conn.commit();
            }else {
                conn.rollback();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                pstmt.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
		return result;
	}

    public int deleteMember(String userId) {
    	Connection conn = null;
    	PreparedStatement pstmt = null;
    	int result = 0;
    	
    	String sql = "DELETE FROM MEMBER WHERE USERID = ?";
    	
    	try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC"
                                             , "JDBC");
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, userId);
			result = pstmt.executeUpdate();
			
			if(result > 0) {
				conn.commit();
			} else {
				conn.rollback();
			}
		} catch (ClassNotFoundException | SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				pstmt.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	    return result;
	}
}
반응형