국비교육(22-23)

22일차(4)/java(33) : JDBC, DTO

서리/Seori 2022. 11. 4. 23:35

22일차(4)/java(33) : JDBC, DTO

 

 

MainClass06

- DB 관련 내용을 분리하지 않은 상태

package test.main;

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

/*
 * JDBC (Java DataBase Connectivity)
 * 
 * DataBase에 연결해서 SELECT, INSERT, UPDATE, DELETE 작업하기
 * 
 * Oracle에 연결하기 위해서는 드라이버 클래스가 들어있는 ojdbc6.jar 파일을
 * 사용할 수 있도록 설정해야 한다. 
 */
public class MainClass06 {
	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();
	      }
	      
	      //시퀀스(member_seq)를 이용해서 회원정보 추가
	      String name="바나나";
	      String addr="서울";
	      	      	      
	  	  //INSERT 작업을 위해서 필요한 객체의 참조값을 담을 지역변수 미리 만들
	      PreparedStatement pstmt=null;	      
	      try {
	    	  //실행할 SQL문
	    	  String sql="INSERT INTO member"
	    			  + " (num, name, addr)"
	    			  + " VALUES(member_seq.NEXTVAL, ?, ?)";
	    	  //PreparedStatement 객체의 참조값 얻어오기
	    	  pstmt=conn.prepareStatement(sql);
	    	  pstmt.setString(1, name);
	    	  pstmt.setString(2, addr);
	    	  //sql문 실행하기
	    	  pstmt.executeUpdate();
	    	  System.out.println("회원 정보를 추가했습니다.");
	      }catch (Exception e){
	    	  e.printStackTrace();
	      }
	}	
}

 

- Primary key는 일반적으로 시퀀스를 이용한다.

- 시퀀스를 이용하면 숫자 관리가 쉽고, ? 의 수가 줄어든다!

 


 

test.util - DBConnect 클래스 생성

- MainClass06에서 DB 파트 분리!

package test.util;

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

public class DBConnect {
	//필드
	Connection conn;
   
	//생성자
	public DBConnect() {
		//Connection 객체의 참조값을 얻어내서 필드에 저장하기 
		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() {
    //필드에 저장된 Connection 객체의 참조값을 리턴해주기 
    return conn;
	}
}

 

MainClass06 (수정)

- DB 관련 내용을 따로 분리!

package test.main;

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

import test.util.DBConnect;

/*
 * JDBC (Java DataBase Connectivity)
 * 
 * DataBase에 연결해서 SELECT, INSERT, UPDATE, DELETE 작업하기
 * 
 * Oracle에 연결하기 위해서는 드라이버 클래스가 들어있는 ojdbc6.jar 파일을
 * 사용할 수 있도록 설정해야 한다. 
 */
public class MainClass06 {
	public static void main(String[] args) {
		 
	      //시퀀스(member_seq)를 이용해서 회원정보 추가
	      String name="바나나";
	      String addr="서울";
	      	      	      
	  	  //INSERT 작업을 위해서 필요한 객체의 참조값을 담을 지역변수 미리 만들
	      Connection conn=null;
	      PreparedStatement pstmt=null;	      
	      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, name);
	    	  pstmt.setString(2, addr);
	    	  //sql문 실행하기
	    	  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) {}
	      }
	}	
}

 

- Connection 객체를 얻어내야 하는데, 매번 복사하려니 불편하다.

→ Connection 객체만 리턴해주는 메소드가 있으면 좋겠다!

- 그런 별도의 클래스를 설계해보기!

 

 

 

Connection c = new DBConnect().getConn();

- DBConnect 클래스 안에 있는 getConn 메소드를 호출한다.

- 이 값을 미리 만들어져 있던 지역변수 안에 넣어서 사용.(여기서는 conn)

- new하면 필드에 들어가고(Connection 타입 참조값을 필드에 넣어두고) .getConn하면 꺼내와진다.

 


 

Member 클래스

package test.mypac;

public class Member {
	public int num;
	public String name;
	public String addr;
}

- mypac 패키지에 새 Member class를 만들고 공개필드도 만들어둠

 

 

MainClass07

package test.main;

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

import test.mypac.Member;
import test.util.DBConnect;

public class MainClass07 {
	public static void main(String[] args) {
		//추가할 회원정보
	    String name="딸기";
	    String addr="부산";
	    
	    //추가할 회원의 정보를 Member 객체에 담고
	    Member mem=new Member();
	    //객체의 필드가 public 공개필드이기 때문에 대입연산자로 직접 참조해서 필드에 값을 대입할 수 있다.
	    mem.name=name;
	    mem.addr=addr;
	    //insert()메소드 호출하면서 Member 객체 전달하기
	    insert(mem);	      
	}
	
	//회원 한명의 정보를 추가하는 메소드를 만들기
	public static void insert(Member m) {
		Connection conn=null;
	    PreparedStatement pstmt=null;	      
	      try {
	    	  //connection 객체의 참조값 얻어오기
	    	  conn=new DBConnect().getConn();
	    	  //실행할 SQL문
	    	  String sql="INSERT INTO member"
	    			  + " (num, name, addr)"
	    			  + " VALUES(member_seq.NEXTVAL, ?, ?)";
	    	  pstmt=conn.prepareStatement(sql);
	    	  pstmt.setString(1, m.name);
	    	  pstmt.setString(2, m.addr);
	    	  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) {}
	    }
	}
}

 

- 이렇게 하나하나 넣으면 번거롭고 힘들다...

 

- '회원 한명의 정보를 저장하는 어떤 메소드'가 완성되어 있다면,
 메인메소드에서 한번에 실행할 수 있다.

- 여러 개의 정보를 하나의 객체에 담아서 전달하기.(보통 단순나열해서 전달하지 않는다)

- 두개의 정보(name, addr)를 객체에 담고 그 참조값을 전달하는 방식으로 바꾸기.

 

- select, insert, update, ... 는 아예 다른 메소드로 분리할 예정!

 


- Member객체의 m.name이라는 필드 / m.addr이라는 필드 사용

- 필드에 넣은 뒤에 참조해서 가져온다!

 


 

MainClass08

- Map, HashMap사용

package test.main;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;

import test.mypac.Member;
import test.util.DBConnect;

public class MainClass08 {
	public static void main(String[] args) {
		//추가할 회원정보
	    String name="딸기";
	    String addr="부산";
	    
	    //추가할 회원의 정보를 HashMap객체에 key:value의 쌍으로 저장한다음
	    Map<String, Object> map=new HashMap<>();
	    map.put("name", name);
	    map.put("addr", addr);
	    
	    //insert()메소드 호출하면서 Map객체를 전달한다.
	    insert(map);
	}
	
	//회원 한명의 정보를 추가하는 메소드를 만들기
	public static void insert(Map<String, Object> m) {
		//Map에 저장된 회원의 이름과 주소를 읽어와서
		String name=(String)m.get("name");
		String addr=(String)m.get("addr");
		//INSERT 작업을 위해서 필요한 객체의 참조값을 담을 지역변수 미리 만들기
		Connection conn=null;
	    PreparedStatement pstmt=null;	      
	      try {
	    	  //connection 객체의 참조값 얻어오기
	    	  conn=new DBConnect().getConn();
	    	  //실행할 SQL문
	    	  String sql="INSERT INTO member"
	    			  + " (num, name, addr)"
	    			  + " VALUES(member_seq.NEXTVAL, ?, ?)";
	    	  pstmt=conn.prepareStatement(sql);
	    	  pstmt.setString(1, name);
	    	  pstmt.setString(2, addr);
	    	  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) {}
	    }
	}
}

- member 객체를 사용하는대신 map을 사용한다. → key-value 가 쌍으로 있는 인터페이스!

 

 

- Map 객체의 값(묶음)을 매개변수 m에 전달하기!

 

- Map에 담아서 설계하면 member 클래스를 따로 만들지 않아도 된다.
 여러 개의 정보를 하나의 묶음으로, 객체에 담아서 전달한 것.

String name=(String)m.get("name");
String addr=(String)m.get("addr");
- map을 사용하면 캐스팅하는 수고가 들어간다. object로 받기 때문에.


 

- 지금은 Member 클래스의 필드가 공개되어 있는데,

 보통 java에서는 필드를 가려두고(private), 메소드를 통해서 접근하게끔 한다.

 

 

MemberDto 클래스

- 접근자 Accessor (etter, setter) 생성

package test.dto;

public class MemberDto {
	//회원 한명의 정보를 저장할 필드(보통 테이블의 칼럼명과 일치시킨다)
	private int num;
	private String name;
	private String addr;
	
	//디폴트 생성자
	public MemberDto() {}

	public MemberDto(int num, String name, String addr) {
		super();
		this.num = num;
		this.name = name;
		this.addr = addr;
	}
	//private 필드를 위한 접근자accessor를 만들어야한다.

	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;
	}	
}

 

MainClass09

- MemberDto 클래스와 insert 메소드 활용

package test.main;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;

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

public class MainClass09 {
	public static void main(String[] args) {
		//추가할 회원정보
	    String name="딸기";
	    String addr="부산";
	    
	    //추가할 회원의 정보를 MemberDto객체에 담아서
	    MemberDto dto=new MemberDto();
	    dto.setName(name);
	    dto.setAddr(addr);
	    
	    //insert()메소드 호출하면서 Map객체를 전달한다.
	    insert(dto);
	}
	
	//회원 한명의 정보를 추가하는 메소드를 만들기
	public static void insert(MemberDto dto) {
		
		//INSERT 작업을 위해서 필요한 객체의 참조값을 담을 지역변수 미리 만들기
		Connection conn=null;
	    PreparedStatement pstmt=null;	      
	      try {
	    	  //connection 객체의 참조값 얻어오기
	    	  conn=new DBConnect().getConn();
	    	  //실행할 SQL문
	    	  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) {}
	    }
	}
}

- DTO : Data Transfer Object

 

- 필드를 private으로 설정해두면 객체 안에서만 접근 가능하고, 외부에서는 해당 필드에 접근할 수 없다.

 

- 디폴트 생성자를 만들고, 이클립스 기능을 사용해서 필드를 사용하는 생성자를 generate 해준다.

- 우클릭-Source-Generate Constructor using Fields

 

- 전체 체크하고 Generate하면 num, name, addr을 인자로 받는

 MemberDto 생성자가 자동으로 만들어진다.

 

- Setter : 값을 넣어주는 메소드

- Getter : 값을 가져오는 메소드

- 전체 체크하면 해당 이름으로 getter, setter가 만들어진다.

 

 

- 접근지정자가 public인 setter, getter가 만들어짐.

- 박스별로 각각 num, name, addr에 해당하는 각각의 accessor이다.

 

 

 

- 처음 생성되었을 때에는 0, null, null이 들어있다

 

dto.num=1;  → X. 이렇게는 접근이 안된다.(필드 직접참조 불가)

dto.setNum(1); O. 값을 넣어주고 싶으면 클래스의 setter 메소드를 사용한다.

 

 

dto.name="kim";  → X.

dto.setName="kim";  → O.

 

- dto에 저장된 이름을 불러오고(참조하고) 싶다면? getter메소드를 사용한다.

int num=dto.num;  → X.

int num-dto.getNum(); → O.

 

- 모두 작성규약이 있어서 dto를 작성 규칙에 맞게 잘 만들어놓으면 자동화하여 처리할 수 있는 것이 많다.

 그래서 이클립스의 generate를 사용한다.

 

- 메소드들은 필드명에 맞춰서 만들어진다.  ex) 필드명이 price라면 setPrice, getPrice

 

setter 메소드를 통해 넣고, getter 메소드를 통해 읽어낸다.

 

 


 

MainClass10

- MemberDto 클래스와 update 메소드 활용

package test.main;

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

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

public class MainClass10 {
	public static void main(String[] args) {
		//수정할 회원의 정보
		int num=1;
		String name="호빵";
		String addr="분식집";
		
		//MemberDto dto=new Member Dto(num, name, addr);
		MemberDto dto=new MemberDto();
		dto.setNum(num);
		dto.setName(name);
		dto.setAddr(addr);
		
		update(dto);
	}	
	
	public static void update(MemberDto dto) {
		
		//INSERT 작업을 위해서 필요한 객체의 참조값을 담을 지역변수 미리 만들기
		Connection conn=null;
		PreparedStatement pstmt=null;
		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());
	  	  	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) {}
		};
	}
}

 

- 저 dto에 번호, 이름, 주소가 담겨 있을 것이라고 가정하고 먼저 코딩해두는 것.


- 메인메소드에서는: update 메소드가 만들어졌을 것이라고 가정하고 new MemberDto 객체를 생성한다.
 update 메소드에서는: dto에 무슨 값이 들어갈 것인지는 모르지만 들어올 것이라 생각하고 메소드를 만들어 둔다.ㅎㅎ

MemberDto dto=new MemberDto();
dto.setNum(num);
dto.setName(name);
dto.setAddr(addr);
//
MemberDto dto=new Member Dto(num, name, addr);

- 위는 객체를 생성해두고 (0,null,null) 인 상태일 때 값을 하나씩 넣어주는 것.

 아래는 처음부터 num, name, addr 인자를 가진 생성자를 호출하는 것!
- 생성자가 두개이기 때문에 둘 중 어느쪽을 쓰든 상관없다.

 

- run 하자 1행이 수정되었다!

 

 

- java에서는 이처럼 객체에 정보를 담아서 전달하고,

 그 데이터를 받아서 DB에 저장하는 등 활용할 일이 매우 많다.