본문 바로가기
뒷북 정리 (국비 교육)/java

[Java] step19. JDBC

by 규글 2022. 5. 3.

step19. JDBC

/*
 *  JDBC ( Java DataBase Connectivity )
 *  
 *  DataBase 에 연결해서 SELECT, INSERT, UPDATE, DELETE 작업하기
 *  
 *  Oracle 에 연결하기 위해서는 드라이버 클래스가 들어있는 ojdbc6.jar 파일을
 *  사용할수 있도록 설정해야 한다.
 */

 JDBC Java DataBase Connectivity의 줄임말로, 말 그대로 java에서 DataBase(DB)에 연결하는 것을 말한다. 이번 우선 ojdbc6.jar 를 다운받아서 project의 build path에 추가해준다. 이것은 java에서 oracle DB에 접속할 때 사용하기 위한 class 들이 들어있는 친구다.

 

- 01

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class MainClass01 {
	public static void main(String[] args) {
		// DB 연결객체를 담을 지역변수 만들기
		Connection conn=null;
		try {
			// 오라클 드라이버 로딩
			Class.forName("oracle.jdbc.driver.OracleDriver");
			// 접속할 DB 의 정보 @아이피주소:port번호:db이름
			String url="jdbc:oracle:thin:@localhost:1521:xe";
			// 계정 비밀번호를 이용해서 Connection 객체의 참조값 얻어오기
			conn=DriverManager.getConnection(url, "scott", "tiger");
			// 예외가 발생하지 않고 여기까지 실행순서가 내려오면 접속 성공이다.
			System.out.println("Oracle DB 접속 성공");
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		// SELECT 작업을 위해서 필요한 객체의 참조값을 담을 지역변수 만들기
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		try {
			// 실행할 sql  문
			String sql="SELECT num,name,addr FROM member"
					+ " ORDER BY num ASC";
			// PreparedStatement 객체의 참조값 얻어오기
			pstmt=conn.prepareStatement(sql);
			// PreparedStatement 객체를 이용해서 query 문 수행하고 결과를 
			// ResultSet 객체로 받아오기
			rs=pstmt.executeQuery();
			while(rs.next()) {
				int num=rs.getInt("num");
				String name=rs.getString("name");
				String addr=rs.getString("addr");
				// 출력하기
				System.out.println(num+" | "+name+" | "+addr);
			}			
		}catch(Exception e) {
			e.printStackTrace();
		}
		System.out.println("main 메소드가 종료 됩니다.");
	}
}

 DB의 table의 data를 select 해오는 예시이다. 예시는 두 단계로 나뉜다. 우선 build path에 추가하여 project의 Reference Library인 ojdbc.6 jar 파일에 있는 class를 사용해서 oracle driver를 로딩하고, 접속할 DB(Data Base)의 정보를 입력한다. 여기에서 localhost는 현재 작업하고 있는 작업 공간의 ip 주소로, '127.0.0.1'을 의미한다. 그리고 DriverManager의 getConnection method에 DB 정보와 oracle 에 접속할 id와 password를 입력해서 Connection 객체에 담는다. 이 부분의 최종 목적은 바로 이 Connection 객체의 참조값을 얻는 것이다.

 

 접속에 필요한 정보들이 잘못되었다면 exception이 발생한다. 왼쪽의 exception은 PC의 서비스에서 표기된 두 가지가 실행되고 있지 않기 때문에 oracle DB에 정상적으로 접근할 수 없어 발생한 것이다.

 오른쪽의 exception은 연결하려고 하는 oracle DB의 ip 주소, port 번호, DB 이름, oracle 계정 정보가 올바르지 않을 때 발생한다. 이럴 경우는 Connection 객체가 정상적으로 생성되지 않는다.

 

 우선 oracle DB에서 수행할 sql 문을 작성한다. 이 sql 문을 Connection 객체의 prepareStatement( ) method에 전달해서 PreparedStatement 객체에 담는다. 글자 그대로 작성한 query 문을 수행할 준비를 한 것이다. 그리고 이어서 이 객체의 executeQuery( ) method를 사용해 query 문을 수행하고, 그 결과를 ResultSet 객체로 받아온다. Execute는 "실행하다, 수행하다." 는 의미이다. 이 ResultSet 객체의 next( ) method는 cursor가 이동하면서 data를 읽어낸다고 생각하면 되는데, 다음 data가 있으면 true를 return하면서 cursor를 다음으로 이동시킨다. Data를 읽을 때 사용하는 get method는 해당 data의 type에 맞는 method를 찾아 사용한다.

 이런 식으로 DB의 table에 있는 정보를 읽어올 수 있다.

 

- 02

		/*
		 *  member  테이블에 추가할 회원의 정보
		 *  1, 김구라, 노량진
		 */
		int num=1;
		String name="김구라";
		String addr="노량진";
        
        // 필요한 객체의 참조값을 담을 빈 지역 변수 미리 만들기
		PreparedStatement pstmt=null;
		try {
			// 실행할 미완성의 sql 문
			String sql="INSERT INTO member"
					+ " (num, name, addr)"
					+ " VALUES(?, ?, ?)";
			// PreparedStatement 객체의 참조값 얻어오기
			pstmt=conn.prepareStatement(sql);
			// ? 에 값을 바인딩해서 미완성의 sql 문을 완성 시킨다.
			pstmt.setInt(1, num); 
			pstmt.setString(2, name);
			pstmt.setString(3, addr);
			// 실제로 수행하기
			pstmt.executeUpdate();
			System.out.println("회원 정보를 저장했습니다.");
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			try {
				// 안전하게 마무리 작업하기 
				if(pstmt!=null)pstmt.close();
			}catch(Exception e) {}
		}

 이번에는 DB table에 data를 insert하는 예시이다. 이전 table의 data를 select 하는 예시와는 다른 점이 세 가지 있다.

 우선 Query 문을 수행하고 난 결과가 없으니 ResultSet 객체가 필요 없다.

 그리고 sql 문에 물음표 '?' 가 존재한다. 이 물음표는 sql 문을 미완성의 상태로 작성해두고 추후 method를 이용해서 해당 자리에 원하는 data를 넣기 위한 목적을 가지고 있다. 생각해보면 이 물음표의 존재는 당연하다. DB의 table에 data 단 하나(혹은 한 줄) 넣고 싶다면 모르겠지만, 해당 자리에 값만 바꿔가면서 계속해서 넣어주고 싶다면 sql 문을 작성하기 정말 곤란할 것이다. 값만 계속 바꿔줄 수 있다면 작업은 보다 단순해질 것이다. 이 물음표가 column에만 들어가는 것은 아니라고 했다.

 마지막으로 다른 점은 get이 아닌 set method를 사용한다는 것과 executeQuery( )가 아닌 executeUpdate( ) method를 사용한다는 것이다. 이 set method는 숫자와 값을 인자로 전달하는데, 숫자는 작성한 sql 문의 물음표의 순서이다. 마찬가지로 get method 처럼 알맞은 type에 맞는 method를 찾아 사용하면 된다.

 

- 03

		/*
		 *  member  테이블에 추가할 회원의 정보
		 *  김구라, 노량진
		 *  회원의 번호는 시퀀스 객체를 이용해서 넣기
		 *  시퀀스 명: member_seq
		 */
		String name="김규환";
		String addr="퍼렁별";

			//실행할 미완성의 sql 문
			String sql="INSERT INTO member"
					+ " (num, name, addr)"
					+ " VALUES( member_seq.NEXTVAL, ?, ?)";
			//PreparedStatement 객체의 참조값 얻어오기
			pstmt=conn.prepareStatement(sql);
			// ? 에 값을 바인딩해서 미완성의 sql 문을 완성 시킨다.
			pstmt.setString(1, name);
			pstmt.setString(2, addr);
			// 실제로 수행하기
			pstmt.executeUpdate();

 DB에 table을 만들 때, 각 row가 구분되도록 number column을 primary key로 설정했었다. 그런데 이전 예제처럼 매 차례 숫자를 넣어줄 수는 없는 노릇이다. 그래서 예전 sql 문 작성법 때 정리했던 sequence를 사용할 수 있다.[각주:1]

 

- 04 ~ -05

		int num=2;
		String name="원숭이";
		
		PreparedStatement pstmt=null;
		try {
			String sql="UPDATE member"
					+ " SET name=?"
					+ " WHERE num=?";
			pstmt=conn.prepareStatement(sql);
			pstmt.setString(1, name);
			pstmt.setInt(2, num);
			pstmt.executeUpdate();
		// 수정할 회원의 정보 
		int num=2;
		String name="신현호";
		String addr="상도동";
		
		PreparedStatement pstmt=null;
		try {
			String sql="UPDATE member"
					+ " SET name=?, addr=?"
					+ " WHERE num=?";
			pstmt=conn.prepareStatement(sql);
			pstmt.setString(1, name);
			pstmt.setString(2, addr);
			pstmt.setInt(3, num);
			pstmt.executeUpdate();

  이번에는 DB data를 update(수정) 하는 두 가지 예시이다. DB 에 insert 하는 예시와 sql 문에서 차이만 있을 뿐이다.

 

- 06

		// 삭제할 회원의 번호 
		int num=3;
		
		PreparedStatement pstmt=null;
		try {
			// 실행할 sql 문
			String sql="DELETE FROM member"
					+ " WHERE num=?";
			pstmt=conn.prepareStatement(sql);
			// ? 에 값 바인딩
			pstmt.setInt(1, num);
			// sql 문 실행하기 
			int flag=pstmt.executeUpdate();
			if(flag > 0) {
				System.out.println("회원 정보를 삭제 했습니다.");
			} else {
				System.out.println("삭제되지 않았습니다.");
			}
			}catch(Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(pstmt!=null)pstmt.close();
			}catch(Exception e) {}
		}

 DB data를 삭제(delete)하는 예시도 이전 insert, update와 동일하다. 큰 문제는 아니지만 약간의 다른 점이 있다면 executeUpdate( ) method의 결과를 받는 변수를 하나 더 만들었다는 것이다. executeUpdate( ) method는 int 값을 return 하는데, 이 값은 DB를 update 한 수에 해당한다. 이를 이용해서 sql 문이 수행된 후의 동작을 나눠서 작성할 수 있다.

 

- 07

import java.sql.Connection;
import java.sql.DriverManager;

public class DBConnect {
	// 필드
	private Connection conn;
	
	// 생성자에서 Connection 객체를 얻어와서 필드에 저장한다.
	public DBConnect() {
		try {
			// 오라클 드라이버 로딩
			Class.forName("oracle.jdbc.driver.OracleDriver");
			// 접속할 DB 의 정보 @아이피주소:port번호:db이름
			String url="jdbc:oracle:thin:@localhost:1521:xe";
			// 계정 비밀번호를 이용해서 Connection 객체의 참조값 얻어오기
			conn=DriverManager.getConnection(url, "scott", "tiger");
			// 예외가 발생하지 않고 여기까지 실행순서가 내려오면 접속 성공이다.
			System.out.println("Oracle DB 접속 성공");
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	// 필드에 저장된 Connection 객체의 참조값을 리턴해주는 메소드
	public Connection getConn() {
		return conn;
	}
}

 - 01 ~ - 06 의 예시에서는 oracle DB에 연결하고 Connection 객체를 만드는 부분이 반복된다. 이렇게 계속해서 반복적으로 사용할 것이라면 차라리 Connection 객체를 만드는 class를 만들고 그 객체를 return 해주는 method를 만들어 사용하는 것이 낫다.

public class MemberDto {
	// 회원 한명의 정보를 담을 필드 선언
	private int num;
	private String name;
	private String addr;
    
	// default 생성자 만들기
	public MemberDto() {}
    
	// 인자로 필드에 저장할 값을 전달 받는 생성자
	public MemberDto(int num, String name, String addr) {
		super();
		this.num = num;
		this.name = name;
		this.addr = addr;
	}
	// 필드의 접근 메소드 setter, getter 메소드 
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}	
}

 이번 예시에서는 DTO (Data Transfer Object) 라는 친구를 사용하였다. 이전에도 이 친구를 만나본 적이 있다.[각주:2] 잊었다면 참고한다.

 

	public static void main(String[] args) {
		/*
		 *  member 테이블에 저장된 모든 회원의 정보를 
		 *  번호에 대해서 오름차순 정렬해서
		 *  List<MemberDto> 객체에 담아 오려고 한다. 
		 */
		
		// 회원 목록을 담을 객체 생성
		List<MemberDto> list=new ArrayList<>();
		
		Connection conn=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		try {
			// DBConnect 객체를 이용해서 Connection 객체의 참조값을 얻어온다.
			conn=new DBConnect().getConn();
			// 실행할 sql 문
			String sql="SELECT num,name,addr"
					+ " FROM member"
					+ " ORDER BY num ASC";
			pstmt=conn.prepareStatement(sql);
			// query 문 수행하고 결과 얻어오기
			rs=pstmt.executeQuery();
			// 반복문 돌면서 select 된 회원정보  읽어오기
			while(rs.next()) {
				// 회원정보를 list 에 담아 보세요.
				int num=rs.getInt("num");
				String name=rs.getString("name");
				String addr=rs.getString("addr");
				// MemberDto 객체를 생성해서 회원 한명의 정보를 담는다.
				MemberDto dto=new MemberDto();
				dto.setNum(num);
				dto.setName(name);
				dto.setAddr(addr);
				// MemberDto 객체를 List 에 누적 시킨다.
				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) {}
		}		
		// 아래의 static 메소드 호출하기
		printMember(list);		
	}// main()
	
	// 회원목록을 콘솔창에 출력해주는 메소드 
	public static void printMember(List<MemberDto> list) {
		for(MemberDto tmp:list) {
			System.out.println(tmp.getNum()+" | "+
					tmp.getName()+" | "+tmp.getAddr());
		}
	}

 Dto 객체에 생성자의 인자로 전달해도 되는데, data의 개수가 많으면 setter method를 활용하는 것이 좋다. 인자로 전달하는 data의 순서가 적어도 헷갈리는데, 그 수가 많아지면 더 헷갈리기 쉽다. 이번 예시를 그림으로 확인하면 다음과 같다.

 그리고 마지막으로 만들었던 객체를 사용했던 순서의 역순으로 닫아준다.

 

- 08

import java.sql.Connection;
import java.sql.PreparedStatement;

import test.dto.MemberDto;
import test.util.DBConnect;

public class MainClass08 {
	public static void main(String[] args) {
		// 추가할 회원의 정보 
		String name="주뎅이";
		String addr="봉천동";
		// 아래의 insert() 메소드를 호출해서 회원 한명의 정보가 추가 되도록 해 보세요.
		
		// 추가할 회원의 정보를 MemberDto 객체에 담고 
		MemberDto dto=new MemberDto();
		dto.setName(name);
		dto.setAddr(addr);
		// insert() 메소드 호출하면서 전달하기 
		insert(dto);
	}
	// MemberDto 객체를 인자로 전달 받아서 회원정보를 DB 에 저장하는 메소드 
	public static void insert(MemberDto dto) {
		Connection conn=null;
		PreparedStatement pstmt=null;
		try {
			conn=new DBConnect().getConn();
			String sql="INSERT INTO member"
					+ " (num, name, addr)"
					+ " VALUES(member_seq.NEXTVAL, ?, ?)";
			pstmt=conn.prepareStatement(sql);
			pstmt.setString(1, dto.getName());
			pstmt.setString(2, dto.getAddr());
			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) {}
		}
	}
}

 이전 - 03 에서의 예시를 main method가 아닌 insert( ) method로 만들고, 이를 main에서 사용한 예시이다. 바로 이전 - 07 예시에서 Dto 객체에 setter method로 정보를 담았다면, 이번에는 Dto 객체로부터 getter method로 정보를 가져왔다. DB에 data를 넣는 insert( ) method에 넣고자 하는 data를 Dto 객체에 담아 insert( ) method에 전달한 것이다. 이렇듯 여러 정보를 전달할 때는 보통 Dto 객체 째로 전달한다.

 

- 09

import java.sql.Connection;
import java.sql.PreparedStatement;

import test.dto.MemberDto;
import test.util.DBConnect;

public class MainClass09 {
	public static void main(String[] args) {
		// 수정할 회원의 정보
		int num=1;
		String name="이정호";
		String addr="독산동";
		// MemberDto 객체에 수정할 회원의 정보를 담아서 
//		MemberDto dto=new MemberDto();
//		dto.setNum(num);
//		dto.setName(name);
//		dto.setAddr(addr);
		
		MemberDto dto=new MemberDto(num, name, addr);
		// 메소드 호출하면서 전달
		update(dto);
	}
	// 인자로 MemberDto 객체를 전달 받아서 DB 에 수정 작업을 하는 메소드 
	public static void update(MemberDto dto) {
		Connection conn=null;
		PreparedStatement pstmt=null;
		try {
			conn=new DBConnect().getConn();
			String sql="UPDATE member"
					+ " SET name=?, addr=?"
					+ " WHERE num=?";
			pstmt=conn.prepareStatement(sql);
			pstmt.setString(1, dto.getName());
			pstmt.setString(2, dto.getAddr());
			pstmt.setInt(3, dto.getNum());
			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) {}
		}
	}
}

  DB 정보를 수정하는 - 04 ~ - 05 의 예시를 - 08 예시와 마찬가지로 Dto 객체에 모든 내용을 전달하여 바꾼 예시이다. 그럼 이제 아래 이미지와 같은 java web application을 상상해보자.

 

 Web application이 위와 같은 구성이라고 생각해보자. 각 게시판은 적힌 기능을 수행해야 한다. 그럼 벌써 보이는 것만 10개의 객체를 만들어야 한다. 너무도 많이 만들어야 하는 것이다. 하지만 이렇게 생각해보면 어떨까? 모든 기능을 가진 객체를 만들어 사용하는 방법이 있다면 기능에 대한 객체 각각을 만드는 방향은 택하지 않을 것이다. 이렇게 모든 기능을 가진 객체를 DAO (Data Access Object) 라고 한다. 말 그대로 data에 접근할 수 있도록 하는 object를 말하며, 추가, 수정, 삭제 등의 방식으로 data에 접근할 수 있게 한다. 다음 예시로 넘어가보자.

 

- 10

/*
 *   DAO (Data Access Object)  의 약자
 *   
 *   - 만드는 방법
 *   
 *   1. 외부에서 객체 생성하지 못하도록 생성자의 접근 지정자를 private 로 지정
 *   2. 자신의 참조값을 저장할 수 있는 필드를 private static 로 선언
 *   3. 자신의 참조값을 오직 하나만 생성해서 리턴해주는 static 메소드 만들기 
 *   4. 나머지 기능(select,insert,update,delete)들은 non static 으로 만들기
 *   
 */

 우선 DAO 객체는 외부에서 생성하지 못하고 class 내에서만 생성할 수 있도록 constructor의 접근 지정자를 private로 지정해야 한다. 그리고 class 내에서 객체의 참조값을 저장할 수 있도록 field를 만드는데, 이때 이 field를 private static으로 선언해준다. 바깥에서는 이 field를 직접 참조할 수 없고, method를 통해 따로 참조값을 받아갈 수 있도록 해야한다. 그래서 이 field에 저장할 참조값을 딱 하나만 생성해서 return 해주는 static method를 만든다. 최초에는 private static field는 null 일 것이기 때문에 객체를 생성해고 return 하도록 만든다. 그리고 나머지 필요한 select, insert, update, delete 등은 non static method로 만든다.

 

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 MemberDao {
	// 자신의 참조값을 저장할 private 필드
	private static MemberDao dao;
	
	// 외부에서 객체 생성하지 못하도록 한다. 
	private MemberDao() {
		System.out.println("MemberDao 객체가 생성되었습니다.");
	}
	
	// 참조값을 리턴해주는 메소드
	public static MemberDao getInstance() {
		if(dao==null) {//최초 호출되면 null 이므로 
			dao=new MemberDao();//객체를 생성해서 static 필드에 담는다. 
		}
		return dao;
	}
	//회원 한 명의 정보를 리턴해주는 메소드
	public MemberDto getData(int num) {
		// 회원 한 명의 정보를 담을 MemberDto 
		MemberDto dto=null;
		
		Connection conn=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		try {
			// DBConnect 객체를 이용해서 Connection 객체의 참조값을 얻어온다.
			conn=new DBConnect().getConn();
			// 실행할 sql 문
			String sql="SELECT name,addr"
					+ " FROM member"
					+ " WHERE num=?";
			pstmt=conn.prepareStatement(sql);
			pstmt.setInt(1, num);
			// query 문 수행하고 결과 얻어오기
			rs=pstmt.executeQuery();
			// 반복문 돌면서 select 된 회원정보 읽어오기
			while(rs.next()) {
				// MemberDto 객체 생성해서 
				dto=new MemberDto();
				// 회원 한 명의 정보를 담는다. 
				dto.setNum(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) {}
		}				
		return dto;
	}
	// 회원 목록을 리턴해주는 메소드
	public List<MemberDto> getList(){
		// 회원 목록을 담을 객체 생성
		List<MemberDto> list=new ArrayList<>();
		
		Connection conn=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		try {
			// DBConnect 객체를 이용해서 Connection 객체의 참조값을 얻어온다.
			conn=new DBConnect().getConn();
			// 실행할 sql 문
			String sql="SELECT num,name,addr"
					+ " FROM member"
					+ " ORDER BY num ASC";
			pstmt=conn.prepareStatement(sql);
			// query 문 수행하고 결과 얻어오기
			rs=pstmt.executeQuery();
			// 반복문 돌면서 select 된 회원정보 읽어오기
			while(rs.next()) {
				// 회원정보를 list 에 담아 보세요.
				int num=rs.getInt("num");
				String name=rs.getString("name");
				String addr=rs.getString("addr");
				// MemberDto 객체를 생성해서 회원 한 명의 정보를 담는다.
				MemberDto dto=new MemberDto();
				dto.setNum(num);
				dto.setName(name);
				dto.setAddr(addr);
				// MemberDto 객체를 List 에 누적시킨다.
				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) {}
		}		
		return list;
	}
	
	// 회원 한 명의 정보를 DB 에서 삭제하는 메소드
	public boolean delete(int num) {
		Connection conn=null;
		PreparedStatement pstmt=null;
		int flag=0;
		try {
			conn=new DBConnect().getConn();
			String sql="DELETE FROM member"
					+ " WHERE num=?";
			pstmt=conn.prepareStatement(sql);
			pstmt.setInt(1, num);
			flag=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) {}
		}
		if(flag>0) {
			return true;
		}else {
			return false;
		}
	}
	
	// 회원 정보를 DB 에 저장하는 메소드 (작업의 성공여부가 boolean 으로 리턴된다)
	public boolean insert(MemberDto dto) {
		Connection conn=null;
		PreparedStatement pstmt=null;
		int flag=0;
		try {
			conn=new DBConnect().getConn();
			String sql="INSERT INTO member"
					+ " (num, name, addr)"
					+ " VALUES(member_seq.NEXTVAL, ?, ?)";
			pstmt=conn.prepareStatement(sql);
			pstmt.setString(1, dto.getName());
			pstmt.setString(2, dto.getAddr());
			// sql 문을 수행하고 변화된  row 의 개수를 리턴 받는다. (1)
			flag=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) {}
		}
		if(flag>0) {
			return true; // 작업 성공이라는 의미에서 true  를 리턴한다.
		}else {
			return false; // 작업 실패라는 의미에서 false  를 리턴한다.
		}
	}
	// 회원 정보를 DB 에서 수정하는 메소드
	public boolean update(MemberDto dto) {
		Connection conn=null;
		PreparedStatement pstmt=null;
		int flag=0;
		try {
			conn=new DBConnect().getConn();
			String sql="UPDATE member"
					+ " SET name=?, addr=?"
					+ " WHERE num=?";
			pstmt=conn.prepareStatement(sql);
			pstmt.setString(1, dto.getName());
			pstmt.setString(2, dto.getAddr());
			pstmt.setInt(3, dto.getNum());
			// update 된 row 의 개수가 반환 된다. 
			flag=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) {}
		}
		if(flag>0) {
			return true;
		}else {
			return false;
		}
	}
}

 필요에 따라 이 method 들이 return 하는 값과 그 type을 지정해줄 수 있다. 회원 한 명의 정보를 return 하거나, 회원들 모두의 정보를 return 해야만 하는 경우는 return 값을 정해주었다. 그리고 insert, update, delete의 경우는 작업 성공 여부를 boolean type으로 return 하도록 했다.

 

 이런 반복되는 구조나 method를 계속해서 타이핑하는 것은 굉장히 번거로운 작업이다. 만약 이런 구조들을 한 번에 작성하고 싶다면 Window > Preferences > temp 작성 > Java 하위의 Templates 에서 작성할 수 있다. Console 창에 메시지를 작성하는 System.out.println( ); 을 바로 작성하는 'syso' 도 바로 이와 같이 작성되어 있는 것이다.

 

import test.dao.MemberDao;
import test.dto.MemberDto;

public class MainClass10 {
	public static void main(String[] args) {
		// 만일 MemberDao 객체의 참조값이 필요 하다면?
		// MemberDao dao=new MemberDao(); 직접 객체 생성 불가
		
		// static 메소드를 이용해서 MemberDao 객체의 참조값을 받아올수 있다.
		MemberDao dao=MemberDao.getInstance();
		// 새로 추가할 회원의 정보라면 
		MemberDto dto=new MemberDto();
		dto.setName("덩어리");
		dto.setAddr("상도동");
		// MemberDao 객체의 메소드를 활용해서 저장할수 있다. 
		dao.insert(dto);
		
		MemberDao dao2=MemberDao.getInstance();
		// 수정할 회원의 정보라면
		MemberDto dto2=new MemberDto(1, "김구라", "독산동");
		dao2.update(dto2);		
	}
}

 만들었던 Dao 객체를 사용하는 예시를 보도록 하자. 만든 Dao class 에서 constructor를 private으로 작성했기 때문에 'new' 를 통해 객체를 생성하는 것이 불가능하다. 그럼 class에 만든 method를 어떻게 이용하는가? 그것을 위해서 Dao 객체의 참조값을 얻어오는 method를 만든 것이다. Method를 통해 객체의 참조값을 얻어오고, 그렇게 얻어온 참조값을 이용해서 만든 기능을 사용할 수 있게 된다.

 이렇게 Dao를 만드는 연습을 충분히 해야한다.

 

 java는 객체 지향 언어이다. 객체를 이용할 때에는 어떻게 객체를 얻어오는지도 알아야 한다. 사실상 Dao 객체는 Connection 객체를 이용해서 동작하도록 만들어졌다. 그리고 그 Dao class를 작성할 때 외부에서 생성할 수 없도록 해당 constructor를 private 로 만들었다. 그렇기 때문에 new 로 객체를 생성할 수 없고, 그래서 method를 통해 객체의 참조값을 얻어올 수 있도록 설계하였다. 즉, 직접적으로 얻어내는 것이 아니라 간접적으로 참조값이 들어있는 field의 값을 return 받아야만 한다. 왜 하필 private으로 만들었을까?

 

 Oracle DB에 연결하기 위해 Connection 객체를 만들어내는데, 이 연결 객체를 무한히 연결할 수는 없다. 연결 객체를 만들 수 있는 수가 정해져있다고 한다. 한 번에 연결할 수 있는 객체의 수가 유한하다는 의미이다. 그런데 이런 상황에 많은 수의 객체를 만들어내려고 하면 잘 안만들어진다고 했다. 그래서 이 Dao를 사용함에 있어서 단 하나의 객체를 사용하기 위해서 private으로 만들었던 것이다.

 

 참고) 특정 class가 미완성인 상태로 작성하려고 할 때, 많은 수의 빨간 줄을 확인할 수 있을 것이다. 이럴 때 해당 밑줄에서 ctrl + space 를 하면 자동으로 import 된다고 했었다. 그런데 이렇게 많은 수를 import 하려고 할 때, 하나씩 하게되면 굉장히 번거로울 수 있다. 이들을 한 번에 import 하고자 할 때는 ctrl + shift + o 를 누르면 된다.

 

- 11

		// MemberDao 객체의 참조값 얻어오기
		MemberDao dao1=MemberDao.getInstance();
		MemberDao dao2=MemberDao.getInstance();
		MemberDao dao3=MemberDao.getInstance();
		// dao1, dao2, dao3 안에 있는 값은 모두 같다 (singleton)
		if(dao1 == dao2) {
			System.out.println("dao1 과 dao2 는 같아요");
		}
		if(dao2 == dao3) {
			System.out.println("dao2 와  dao3 는 같아요");
		}

 만들어둔 Dao 객체의 참조값을 얻어보면 값이 모두 같음을 알 수 있다. 이를 singleton(싱글톤)이라고 한다. 이 singleton은 software의 design pattern 중에 하나라고 한다. 객체에 대한 단 하나의 참조값만을 만들어내는 방식이라고 한다. (단 하나의 instance를 만들어낸다고도 한다.)

 

- 12 ~ - 14

		/*
		 *  Scanner 객체를 이용해서 문자열을 두번 입력 받는다.
		 *  즉 새로 추가할 이름과 주소를 입력 받아서 
		 *  MemberDao 객체를 이용해서 DB 에 저장하는 code 를 작성해 보세요. 
		 */
		
		// Scanner 객체를 이용해서 이름과 주소를 문자열로 입력 받기 
		Scanner scan=new Scanner(System.in);
		System.out.print("이름 입력:");
		String name=scan.nextLine();
		System.out.print("주소 입력:");
		String addr=scan.nextLine();
		
		// 이름과 주소를 MemberDto 객체에 저장하기
		MemberDto dto=new MemberDto();
		dto.setName(name);
		dto.setAddr(addr);
		
		// MemberDao 객체의 참조값 얻어오기
		MemberDao dao=MemberDao.getInstance();
		
		// MemberDao 객체의 메소드를 이용해서 DB  에 저장하기
		boolean isSuccess=dao.insert(dto);

 

		/*
		 *  MemberDao 객체를 이용해서 회원 목록을 얻어와서
		 *  아래와 같은 형식으로 출력해 보세요.
		 *  
		 *  1 | 김구라 | 노량진
		 *  2 | 원숭이 | 상도동
		 *  3 | 주뎅이 | 봉천동
		 *  .
		 *  .
		 */
		// MemberDao 객체의 참조값 얻어오기 
		MemberDao dao=MemberDao.getInstance();
		// MemberDao 객체의 메소드를 이용해서 회원목록 얻어오기 
		List<MemberDto> list=dao.getList();
		// 반복문 돌면서 원하는 형식으로 출력하기
		for(int i=0; i<list.size(); i++) {
			MemberDto tmp=list.get(i);
			System.out.println(tmp.getNum()+" | "+tmp.getName()+
					" | "+tmp.getAddr());
		}
		System.out.println("-------------------");
		for(MemberDto tmp:list) {
			System.out.println(tmp.getNum()+" | "+tmp.getName()+
					" | "+tmp.getAddr());
		}

 

		/*
		 *  Scanner 객체를 이용해서 검색할 회원 번호를 입력 받아서
		 *  입력 받은 번호에 해당되는 회원 정보를 얻어와서
		 *  아래와 같은 형식으로 출력해 보세요.
		 *  
		 *  만일 1을 입력한 경우 
		 *  
		 *  1 | 김구라 | 노량진
		 *  
		 *  만일 입력한 번호가 없는 경우
		 *  
		 *  9 번 회원은 존재 하지 않습니다.
		 */
		// Scanner 객체를 이용해서 정수를 입력 받고 
		Scanner scan=new Scanner(System.in);
		System.out.print("검색할 회원 번호 입력:");
		int num=scan.nextInt();
		
		// MemberDao 객체를 이용해서 입력한 회원 정보를 MemberDto 에 담아 온다.
		MemberDao dao=MemberDao.getInstance();
		// 입력한 번호에 해당하는 회원 정보가 없으면 null 이 리턴된다.
		MemberDto dto=dao.getData(num);
		
		if(dto == null) {// 회원 정보가 없는 경우 
			System.out.println(num+" 번 회원은 존재 하지 않습니다.");
		}else {// 회원정보가 있는 경우
			System.out.println(dto.getNum()+" | "+dto.getName()
			+" | "+dto.getAddr());
		}

- 12 ~ - 14 의 예시는 만든 Dao를 이용하는 예시이다.

'뒷북 정리 (국비 교육) > java' 카테고리의 다른 글

Tomcat server 다운로드 / 몇 가지 설정  (0) 2022.05.18
[Java] step20. String  (0) 2022.05.11
[Java] step18. Socket  (0) 2022.04.28
[Java] step17. InputOutput  (0) 2022.04.25
[Java] step16. Thread  (0) 2022.04.25

댓글