[ 국비교육 ] Day 32

19825 단어 일상일상

한 달동안 매주 보던 평가가 막을 내렸다.
물론 다 끝났다는 말은 아니구....

앞으로도 볼 평가는 산더미이지만, 오늘 파트까지 하면 딱!
기본 자바랑 DB 파트가 끝이 난다.

내일부터는 신나는 WEB!! 을 들어가신다. HTML, CSS, JS 등 할게 산더미 😎
프롤로그가 끝이 나고 메인 페이지로 가는 기분이다.

물론 내 인생은 베르세르크라 프롤로그만 수십년이겠지만, 그래도 뭔가 다시 한발 내딛는 기분 자체는 좋다 ⛷️


서술형

1. Statement객체와 PreparedStatement객체에 대해 서술한 후 그 차이점에 대해 서술하시오.

//Statement
Connection con = DriverManager("URL","계정","비밀번호");
Statement state = con.createStatement();
int result = state.executeUpdate(SQL);

// Prepaedstatement 
String SQL = "delete from table where id=?;"
Connection con = DriverManager("URL","계정","비밀번호");
Prestement pstate = con.createPrestement(String SQL);
pstate.setInt(1, 1000);
int result = pstate.executeUpdate();

Statement, PreparedStatement 는 SQL 워크시트의 기능을 가진 객체이다.
Connection 객체의 메서드를 통해 DBMS와 연결되어 불러올 수 있지만 사용법과 기능의 차이가 있다.

  • SQL의 위치가 다르다.
    Statement는 DBMS에 값을 넣을 때, SQL문을 직접 작성해서 넣는 반면, PreparedStatement 객체를 생성하면서 SQL문을 넣어준다.

  • SQL문의 작성법이 다르다.
    Statement는 문자열 연결 연산자로 SQL문을 만들어줘야 하는 반면에, PreparedStatement는 위치홀더('?')를 통해 빈칸을 만들어주고 setter들을 통해서 그 값을 입력할 수 있다.

  • 보안성이 다르다. 전자의 경우, 전달하는 쿼리문을 통해서 SQL 주입에 의한 해킹이 가능하다는 취약점이 있다. 하지만 후자는 그 가능성을 내부적으로 막아놓고 있다.

  • 성능면에서도 PreparedStatement가 더 좋다.

  • Statement를 상속받은 클래스가 PreparedStatement 이다.


2. PreparedStatement에서 사용하는 위치홀더('?')란 무엇인지 서술한 후, ResultSet객체에 대해 서술하시오.

(1) 위치홀텍스트더는 PreparedStatement에 들어가는 SQL문에 '빈칸'의 역할을 한다.

쿼리문을 통해서 특정값들을 가변적으로 입력하고 싶을 때, Statement에서는 문자열 연결로 쿼리문을 짜야했지만 PreparedStatement를 사용하면 위치홀더에 해당하는 부분을 메서드를 통해서 입력해줄 수 있다.

String SQL = "delete from table where id=?;"
Prestement pstate = con.createPrestement(String SQL);
pstate.setInt(1, 1000);

(2) 우리가 DQL을 통해서 DB로부터 응용프로그램으로 값을 받아올 때, ResultSet 객체가 반환된다.

ResultSet 은 주소로서 DBMS에서 출력한 결과가 메모리 상에 올려져있는 위치를 저장하는데, 처음에 해당하는 부분은 헤더라인의 레코드에서 시작한다.

따라서 처음 값을 출력할 때는 ResultSet의 멤버메서드인 .next() 를 통해 한 행을 내려되며, 그 행에 값이 있다면 true , 없으면 false 를 반환한다.

또한 주소로 이어진 연결이기 때문에 JDBC를 통한 DBMS와의 연결이 끊이면 그 값을 반환할 수 없음으로 미리 DTO를 통해 데이터를 옮겨담는다.


3. Statement객체의 SQL문을 수행을하는 executeQuery()와 executeUpdate()를 비교하면서 그 차이점을 서술하시오.

JDBC를 통해 인자값으로 전달된 SQL문을 DBMS에 전달하는 역할을 가지고 있다.
다만 executeUpdate()는 실제 DB에 작업 결과를 반영할 때, executeQuery()는 DB로부터 select문을 통한 탐색을 통해 결과를 출력할 때 사용한다.

  • executeUpdate()는 반환값으로 작업 결과의 성공여부에 대한 int값을 반환.
    int result = state.executeUpdate("delete from table");

  • executeQuery()는 출력된 결과 데이터에 대한 주소를 ResultSet으로 반환한다.
    ResultSet rs = state.executeQuery("select * from table" );


문제해결

[ 문제 ]

쇼핑몰 회원정보를 조회하는 소스코드를 작성하고, 해당 코드를 실행시켰을때 정상적으로 실행할 수 없는 문제가 발생하였다. 소스코드를 분석하여 어떤 오류가 있는지 모두 찾아서 서술한 후 그에 대한 원인과 조치내용(해결방법)을 서술하시오.

public ShopMember searchUser(String memberId) {

Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
ShopMember shopMember = null;

String query = "SELECT * FROM SHOP_MEMBER WHERE MEMBER_ID =" + memberId;

try {

	conn 
    = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", 	"test_01", "T3sxl!&00");

	stmt = conn.createStatement();
	rset = stmt.executeQuery(query);

	if(rset.next()) {

		shopMember.setMemberId(rset.getString("MEMBER_ID"));
		shopMember.setMemberPw(rset.getString("MEMBER_PW"));
		shopMember.setPhone(rset.getString("PHONE"));
		shopMember.setGender(rset.getString("GENDER"));

	}

} catch (SQLException e) {
	e.printStackTrace();

} finally {

	rset.close();
	stmt.close();
	conn.close();
}
return shopMember;
}

* ShopMember Class

public class ShopMember {

	private String memberId;

	private String memberPw;

	private String phone;
	
	private char gender;

	public ShopMember() {}

	public String getMemberId() {

		return memberId;

	}

	public void setMemberId(String memberId) {

		this.memberId = memberId;

	}

	public String getMemberPw() {

		return memberPw;

	}

	public void setMemberPw(String memberPw) {

		this.memberPw = memberPw;

	}

	public String getPhone() {

		return phone;

	}

	public void setPhone(String phone) {

		this.phone = phone;

	}

	public char getGender() {

		return gender;

	}

	public void setGender(char gender) {

		this.gender = gender;

	}
}

원인

1. 드라이버 로딩 x

JDBC API에서 DBMS와 연결할 오라클 드라이버를 JVM에 올려놓지 않았다.
따라서 conn = DriverManager.getConnection 에서 드라이버를 찾지 못해 DBMS와 연결할 수 없다.

2. shopMember.setGender(rset.getString('Gender'));

setGender의 인자값은 문자이다. 그러나 rset.getString('Gender') 은 M, F만 반환하더라고 그 형이 String이기 때문에 예외가 발생한다.

3. 메서드 예외 처리 x

드라이버가 로딩되지 않거나, 연결이 안될 경우에 대해서 예외가 발생할 수도 있다.
이에 대해 메서드가 어떻게 처리할지 설정되어 있지 않아서 에러가 발생한다.

4. 쿼리문 오류

String query = "SELECT * FROM SHOP_MEMBER WHERE MEMBER_ID =" + memberId; 

memberId 는 스트링이 맞지만, 쿼리문 내에서 문자는 ''(홑따옴표)로 감싸줘야 인식이 된다.
이를 하지 않아서 쿼리문 자체에서 에러가 발생했다.

5. ShopMember shopMember = null;

DTO인 shopMember​ 인스턴스를 생성하지 않아서 값을 받아놓지 않아서 Nullpointerexception 이 발생한다.


해결

1. Reflection 기법을 이용한 드라이버 로딩

Class.forName("oracle.jdbc.driver.OracleDriver");

try 구문 맨 첫줄에 넣어서 드라이버를 먼저 메모리에 로딩한다.

2. char형으로 형변환하기

setGender는 char형을 인자값으로 받는다 따라서 rset.getString('Gender') 으로 들어오는 값을 형변환 해준다.

String gender = rset.getString("GENDER");
shopMember.setGender(gender.charAt(0));

3. searchUser메서드에 예외전가 처리
searchUser 는 Callee, 연결을 닫기 위해 finally 를 사용하므로 try-catch를 썻지만, 예외 처리는 Caller에서 해줘야 한다. 따라서 메서드 선언부에 throws Exception 를 입력해준다.

public ShopMember searchUser(String memberId) throws Exception

4. 쿼리 재작성

String query = "SELECT * FROM SHOP_MEMBER WHERE MEMBER_ID ='" + memberId+"'"

DBMS에서 쿼리를 인식하도록 ''(홑따옴표)를 붙여준다.

5. DTO 생성

ShopMember shopMember = new ShopMember(); 

데이터를 보관할 인스턴스를 생성해준다.

좋은 웹페이지 즐겨찾기