23일차(1)/java(34) : JDBC, DAO
MainClass11
- DELETE 메소드 분리하기
package test.main;
import java.sql.Connection;
import java.sql.PreparedStatement;
import test.dto.MemberDto;
import test.util.DBConnect;
public class MainClass11 {
public static void main(String[] args) {
//삭제할 회원의 번호라고 하자
int num=3;
delete(num);
}
//인자로 전달한 번호에 해당하는 회원 한명의 정보를 삭제하는 메소드
public static void delete(int num) {
//DELETE 작업을 위해서 필요한 객체의 참조값을 담을 지역변수 미리 만들기
Connection conn=null;
PreparedStatement pstmt=null;
try {
//connection 객체의 참조값 얻어오기
conn=new DBConnect().getConn();
//실행할 SQL문
String sql="DELETE FROM member"
+ " WHERE num=?";
//PreparedStatement 객체의 참조값 가져오기
pstmt=conn.prepareStatement(sql);
//?에 값 바인딩하기
pstmt.setInt(1, num);
pstmt.executeUpdate();
System.out.println("회원 정보를 삭제했습니다.");
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
}catch(Exception e) {}
};
}
}
- update, insert, delete문은 전부 형태가 같다. 실행할 SQL문과 바인딩할 ?의 값만 잘 수정하면 된다.
- .setInt 에 숫자 바인딩, setString에 문자열 바인딩
- 삭제하는 메소드가 미리 존재한다면 해당 메소드를 사용해서 삭제하기만 하면 되어서 사용이 편리하다.
- 메소드를 미리 준비해놓고 활용하는 연습!
MainClass12
- SELECT문 메소드 분리! (전체 회원의 정보 리턴)
package test.main;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import test.dto.MemberDto;
import test.util.DBConnect;
public class MainClass12 {
public static void main(String[] args) {
//여기서 전체 회원의 목록이 필요하면
//getList() 메소드를 호출하는 것만으로 전체 회원목록을 얻어낼 수 있다.
List<MemberDto> list=getList();
for(MemberDto tmp:list) {
System.out.println(tmp.getNum()+" | "+tmp.getName()+" | "+tmp.getAddr());
}
}
//전체 회원의 목록을 리턴해주는 메소드
public static List<MemberDto> getList() {
//회원 전체 목록을 담을 ArrayList 객체를 생성해서 참조값을 List 인터페이스 type으로 담기
List<MemberDto> list=new ArrayList<>();
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try {
//connection 객체의 참조값 얻어오기
conn=new DBConnect().getConn();
//실행할 SQL문
String sql="SELECT num, name, addr"
+ " FROM member"
+ " ORDER BY num ASC";
//PreparedStatement 객체의 참조값 가져오기
pstmt=conn.prepareStatement(sql);
//?에 값 바인딩하기
rs=pstmt.executeQuery();
while(rs.next()) {
//커서가 위치한 곳의 회원정보를 MemberDto 객체에 담기
MemberDto dto=new MemberDto();
dto.setNum(rs.getInt("num"));
dto.setName(rs.getString("name"));
dto.setAddr(rs.getString("addr"));
//회원 한명의 정보가 담긴 MemberDto 객체의 참조값을 ArrayList 객체에 누적시키기
list.add(dto);
}
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(rs!=null)rs.close();
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
}catch(Exception e) {}
}
//모든 회원의 정보가 누적된 ArrayList 객체이 참조값 리턴해주기
return list;
}
}
- 전체 회원목록의 리턴타입은?
멤버 한명 : MemberDto 타입
멤버 여러명 : List<MemberDto> 타입
→ List<MemberDto> 타입으로 받는 이유는? 회원정보를 목록(리스트) 형태로 받기 위해서!
- 결과를 받는 변수는 ResultSet (rs) 타입을 사용한다.
- while문을 돌면서 값을 불러와서 결과를 resultSet에 넣는다.
select 된 결과값 테이블이 resultSet 안에 들어있게 되는 것!
- insert, delete, update에서 사용하던 pstmt.executeUpdate(); 대신에
pstmt.executeQuery(); 를 쓴다. executeQuery는 쿼리에서 resultSet을 반환하는 메소드이다.
- ResultSet 타입의 결과값을 가져와야 하기 때문에!
- ResultSet에서는 행마다 커서를 하나씩 내리면서 추출한다!
커서가 하나씩 내려오면서 값을 가져온다. → 반복 for문 돌기
- new MemberDto(); 로 담아야 하는데, row 하나 당 MemberDto 값 하나가 나온다!
→ ArrayList에 담어서 리턴한다.
- getList 라는 완전한 형태의 메소드가 미리 만들어져 있다면,
사용자(메인메소드) 입장에서는 getList만 사용하면 된다. 어떻게 사용할지만 고려하면 된다.

- MemberDto의 참조값을 내보낼 수 있도록 리스트에 추가해준다!

- getList 메소드의 작동방식.
dto.setNum/setName/setAddr 로 가져온 값(참조값)을 ArrayList객체에 담아서 마지막에 리턴하도록 한다.

- 디버그모드. while문을 한바퀴씩 돌때마다 각각의 방에 값이 들어가는 것을 확인할 수 있다.
- .next() 메소드를 사용해서 커서를 하나씩 내리며 다음에 값이 있는지 없는지 확인!

- Main메소드의 for문을 돌 때마다 List에 값이 들어간다.
- 사물함 안에 만들어둔 ArrayList를 넣어두고, 마지막에 return list; 로 넣어둔 59번 사물함 키를 리턴해주는 것.
- 디버그모드에서 F5 누르면 메소드 안으로 추적해서 들어갈 수 있다.
MainClass13
- SELECT문 메소드 분리! (특정 회원의 정보 리턴)
package test.main;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import test.dto.MemberDto;
import test.util.DBConnect;
public class MainClass13 {
public static void main(String[] args) {
//메소드를 호출해서 인자로 전달한 번호에 해당하는 회원정보를 얻어오기
MemberDto dto=getData(2);
if(dto==null) {
System.out.println("해당 회원은 존재하지 않습니다.");
}else {
System.out.println("번호: "+dto.getNum()+" 이름: "+dto.getName()+" 주소:"+dto.getAddr());
}
}
//인자로 전달된 번호에 해당하는 회원 한명 한명의 정보를 리턴하는 메소드
//번호에 해당하는 회원의 정보가 없으면 null을 리턴
public static MemberDto getData(int num) {
//MemberDto 객체의 참조값을 담을 지역변수 미리 만들기
MemberDto dto=null;
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try {
//connection 객체의 참조값 얻어오기
conn=new DBConnect().getConn();
//실행할 미완성의 SQL문
String sql="SELECT num, name, addr"
+ " FROM member"
+ " WHERE num=?";
//PreparedStatement 객체의 참조값 가져오기
pstmt=conn.prepareStatement(sql);
//?에 값 바인딩하기
pstmt.setInt(1, num);
rs=pstmt.executeQuery();
//만일 cursor를 한칸 내릴 수 있다면(select 된 row가 있다면)
if(rs.next()) {
//MemberDto 객체를 생성해서 참조값을 미리만들어진 지역변수 dto에 담기
dto=new MemberDto();
//cursor가 위치한곳의 회원정보를 MemberDto 객체에 담기
dto.setNum(rs.getInt("num"));
dto.setName(rs.getString("name"));
dto.setAddr(rs.getString("addr"));
}
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(rs!=null)rs.close();
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
}catch(Exception e) {}
}
//회원 한명의 정보를 담고 있는 MemberDto 객체 리턴해주기
return dto;
}
}
- 안에서 지역변수를 만들면 나중에 null이 반환될 수 없으므로, MemberDto dto=null; 이라고 위에서 선언해둔다.
- 여기서 하는 select는 row가 하나(선택된 회원정보만 보는 것이라서) 나오므로
정렬은 따로 필요없고 대신 where 문을 사용!
- resultset에서 커서를 내려서 읽는것도 한번만 하면 된다.
- select문에서도 ? 사용이 가능하다. ? 자리에 똑같이 바인딩해주면 된다.
dto=new MemberDto(); (값 대입)
- 위에서 변수를 만들어두었기 때문에 변수를 새로 만들 필요는 없고, 그대로 사용한다.
- ArrayList나 List 형태는 필요없기 때문에 dto 객체를 사용하고,
값을 얻어내기 위해 여러번 반복해 도는 것이 아니므로 while대신에 if를 사용한다.
test.dao 패키지 / MemberDao 클래스 생성
- insert, update, delete, getList, getData 메소드 분리
package test.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import test.dto.MemberDto;
import test.util.DBConnect;
/*
* Data Access Object 만들어보기
* - DB에 insert, update, delete, select 작업을 대신해주는 객체를 생성할 클래스 설계하기
*/
public class MemberDao {
//회원 한명의 정보를 저장하고 작업의 성공 여부를 리턴해주는 메소드
public boolean insert(MemberDto dto) {
Connection conn=null;
PreparedStatement pstmt=null;
//수정된 row의 갯수를 담을 지역변수를 미리 만들고 초기값 0 대입하기
int rowCount=0;
try {
//connection 객체의 참조값 얻어오기
conn=new DBConnect().getConn();
//실행할 SQL문
String sql="INSERT INTO member"
+ " (num, name, addr)"
+ " VALUES(member_seq.NEXTVAL, ?, ?)";
//PreparedStatement 객체의 참조값 가져오기
pstmt=conn.prepareStatement(sql);
//?에 값 바인딩하기
pstmt.setString(1, dto.getName());
pstmt.setString(2, dto.getAddr());
//sql 문 실행하고 변화된(추가,수정,삭제) row의 개수를 리턴받기
rowCount=pstmt.executeUpdate();
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
}catch(Exception e) {}
}
//변화된 rowCount의 값을 확인해서 작업의 성공여부를 리턴해준다.
if (rowCount>0) {
return true;
}else{
return false;
}
}
//회원 한명의 정보를 수정하고 작업의 성공 여부를 리턴해주는 메소드
public boolean update(MemberDto dto) {
Connection conn=null;
PreparedStatement pstmt=null;
//수정된 row의 갯수를 담을 지역변수를 미리 만들고 초기값 0 대입하기
int rowCount=0;
try {
//connection 객체의 참조값 얻어오기
conn=new DBConnect().getConn();
//실행할 SQL문
String sql="UPDATE member"
+ " SET name=?, addr=?"
+ " WHERE num=?";
//PreparedStatement 객체의 참조값 가져오기
pstmt=conn.prepareStatement(sql);
//?에 값 바인딩하기
pstmt.setString(1, dto.getName());
pstmt.setString(2, dto.getAddr());
pstmt.setInt(3, dto.getNum());
//sql 문 실행하고 변화된(추가,수정,삭제) row의 개수를 리턴받기
rowCount=pstmt.executeUpdate();
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
}catch(Exception e) {}
}
//변화된 rowCount의 값을 확인해서 작업의 성공여부를 리턴해준다.
if (rowCount>0) {
return true;
}else{
return false;
}
}
//회원 한명의 정보를 삭제하고 작업의 성공 여부를 리턴해주는 메소드
public boolean delete(int num) {
Connection conn=null;
PreparedStatement pstmt=null;
//수정된 row의 갯수를 담을 지역변수를 미리 만들고 초기값 0 대입하기
int rowCount=0;
try {
//connection 객체의 참조값 얻어오기
conn=new DBConnect().getConn();
//실행할 SQL문
String sql="DELETE FROM member"
+ " WHERE num=?";
//PreparedStatement 객체의 참조값 가져오기
pstmt=conn.prepareStatement(sql);
//?에 값 바인딩하기
pstmt.setInt(1, num);
//sql 문 실행하고 변화된(추가,수정,삭제) row의 개수를 리턴받기
rowCount=pstmt.executeUpdate();
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
}catch(Exception e) {}
}
//변화된 rowCount의 값을 확인해서 작업의 성공여부를 리턴해준다.
return rowCount>0 ? true:false;
}
//전체 회원의 목록을 리턴해주는 메소드
public List<MemberDto> getList() {
//회원 전체 목록을 담을 ArrayList 객체를 생성해서 참조값을 List 인터페이스 type으로 담기
List<MemberDto> list=new ArrayList<>();
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try {
//connection 객체의 참조값 얻어오기
conn=new DBConnect().getConn();
//실행할 SQL문
String sql="SELECT num, name, addr"
+ " FROM member"
+ " ORDER BY num ASC";
//PreparedStatement 객체의 참조값 가져오기
pstmt=conn.prepareStatement(sql);
//?에 값 바인딩하기
rs=pstmt.executeQuery();
while(rs.next()) {
//커서가 위치한 곳의 회원정보를 MemberDto 객체에 담기
MemberDto dto=new MemberDto();
dto.setNum(rs.getInt("num"));
dto.setName(rs.getString("name"));
dto.setAddr(rs.getString("addr"));
//회원 한명의 정보가 담긴 MemberDto 객체의 참조값을 ArrayList 객체에 누적시키기
list.add(dto);
}
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(rs!=null)rs.close();
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
}catch(Exception e) {}
}
//모든 회원의 정보가 누적된 ArrayList 객체이 참조값 리턴해주기
return list;
}
//인자로 전달된 번호에 해당하는 회원 한명 한명의 정보를 리턴하는 메소드
//번호에 해당하는 회원의 정보가 없으면 null을 리턴
public MemberDto getData(int num) {
//MemberDto 객체의 참조값을 담을 지역변수 미리 만들기
MemberDto dto=null;
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try {
//connection 객체의 참조값 얻어오기
conn=new DBConnect().getConn();
//실행할 미완성의 SQL문
String sql="SELECT num, name, addr"
+ " FROM member"
+ " WHERE num=?";
//PreparedStatement 객체의 참조값 가져오기
pstmt=conn.prepareStatement(sql);
//?에 값 바인딩하기
pstmt.setInt(1, num);
rs=pstmt.executeQuery();
//만일 cursor를 한칸 내릴 수 있다면(select 된 row가 있다면)
if(rs.next()) {
//MemberDto 객체를 생성해서 참조값을 미리만들어진 지역변수 dto에 담기
dto=new MemberDto();
//cursor가 위치한곳의 회원정보를 MemberDto 객체에 담기
dto.setNum(rs.getInt("num"));
dto.setName(rs.getString("name"));
dto.setAddr(rs.getString("addr"));
}
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(rs!=null)rs.close();
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
}catch(Exception e) {}
}
//회원 한명의 정보를 담고 있는 MemberDto 객체 리턴해주기
return dto;
}
}
- DTO : Data Transfer Object
- DAO : Data Access Object

public boolean insert(MemberDto dto) {}
- public void 는 작업 성공여부와 상관없이 메소드만 호출하는 것
- public boolean 은 작업을 하고, 성공여부에 따라 t/f를 반환하는 것
- insert, update, delete라는 메소드 3개를 위와 같은 틀, 형태로 만들어볼 예정!

.executeUpdate : DML의 영향을 받은 row의 개수를 리턴해준다.
- 입력, 수정, 삭제된 행의 숫자를 리턴하는 것.
- 리턴해주는 숫자가 0보다 크면 작업이 성공이라는 뜻. 0이면 실패했다는 뜻!
- 성공 여부를 판별하여 리턴하는 데에 사용하기!
int rowCount=pstmt.executeUpdate(); executeUpdate의 숫자를 변수에 담아서 if 로 분기하기

- 하지만 이 위치에 if~else문이 만들어지면 아래로 내려가지 못한다!
- try절에서 리턴값이 이미 나와버리므로 마무리작업(finally절)을 할 수 없다.
- finally절까지 종료한 후에 하단에서 if절을 활용해야 한다.

- 그런데 if절을 아래로 빼면 지역변수 rowCount를 참조할 수 없다.

- 따라서 rowCount라는 변수도 위에서 미리 선언해준다.(0 상태로)
- 이렇게 변수를 먼저 선언한 후 나중에 값을 대입하는 구조는 자주 쓰이니까 잘 기억하기!
- Update, Delete 도 똑같이 수정!
if (rowCount>0) {
return true;
}else{
return false;
}
//
return rowCount>0 ? true:false;
- 같은 식! if~else 문은 위와 같이 3항연산자 형태로 쓸 수도 있다.

- 저번에 만든 메소드들을 이 클래스로 가져와서 정리하기.
MainClass14
- DAO 활용방법(INSERT)
package test.main;
import test.dao.MemberDao;
import test.dto.MemberDto;
public class MainClass14 {
public static void main(String[] args) {
//추가할 회원의 정보라고 가정
String name="복숭아";
String addr="대전";
/*
* 회원의 정보를 DB에 저장하는 기능을 가지고 있는
* MemberDao객체를 생성해서 참조값을 dao라는 지역변수에 담기
*/
MemberDao dao=new MemberDao();
//insert() 메소드에 전달할 MemberDto 객체 생성
MemberDto dto=new MemberDto();
//추가할 회원의 정보를 담고
dto.setName(name);
dto.setAddr(addr);
//MemberDao 객체를 이용해서 회원 정보를 추가하고 성공여부를 리턴받는다.
boolean isSuccess=dao.insert(dto);
//성공 여부에 따라 다른 동작을 한다.
if(isSuccess) {
System.out.println(name+"의 정보를 추가했습니다.");
}else {
System.out.println("회원정보 추가 실패!");
}
}
}
- 메소드가 다른 곳에 미리 만들어져 있다면 이렇게 간단하게 메인메소드만 작성 가능하다.
- 데이터베이스 접속방법 등 다른 것들을 신경쓰지 않아도 메소드 활용 가능! (부분 프로그래밍)

- 잘 추가되어 있다.
- UPDATE 연습해본것
package test.main;
import test.dao.MemberDao;
import test.dto.MemberDto;
public class MainTest {
public static void main(String[] args) {
//추가할 회원의 정보라고 가정
int num=2;
String name="사과";
String addr="문경";
/*
* MemberDao객체를 생성해서 참조값을 dao라는 지역변수에 담기
*/
MemberDao dao=new MemberDao();
MemberDto dto=new MemberDto();
dto.setNum(num);
dto.setName(name);
dto.setAddr(addr);
boolean isSuccess=dao.update(dto);
if(isSuccess) {
System.out.println(name+"의 정보를 수정했습니다.");
}else {
System.out.println("회원정보 수정 실패!");
}
}
}

- 수정할 정보를 dto에 담아서 MemberDao 클래스 안에 있는 insert 메소드에 전달하면 알아서 저장해준다.

- 다른 클래스에 있는 update 메소드를 불러와서 사용하기. 잘 수정된다!
참고) SQL의 시퀀스 값은 일정 개수는 미리 만들어져 있다. 언제든 불러내어 사용할 수 있도록!
그런데 그 미리 얻어놓은 시퀀스들은 재부팅하면 사라진다.(캐시 데이터)
시퀀스의 숫자는 '겹치지 않는 숫자'라는 것이 중요하고, 연속성이 필수인 것은 아니다. 값이 중간에 빠져있을 수도 있다!
'국비교육(22-23)' 카테고리의 다른 글
24일차(1)/java(36) : JDBC 실습예제 (Friend 프레임) (0) | 2022.11.08 |
---|---|
23일차(2)/java(35) : JDBC 실습예제 (0) | 2022.11.08 |
22일차(4)/java(33) : JDBC, DTO (0) | 2022.11.04 |
22일차(3)/java(32) : JDBC (0) | 2022.11.04 |
22일차(2)/java(31) : Input, Output(3) (1) | 2022.11.04 |