💁‍♀️ JDBC(Java DataBase Connectivity)란,
자바에서 데이터베이스에 접근할 수 있게 해주는 Programming API


👀 Oracle JDBC Driver 등록

💁‍♀️ DriverManager에 해당 DBMS Driver 등록

[1] Oracle에서 ojdbc8.jar 파일 복사 (미리 경로 확인)

[2] 해당 프로젝트에 'lib'폴더 생성 > 안에 ojdbc8.jar 파일 삽입

[3] 해당 프로젝트 우클릭 > Properties > Java Build Path > Classpath > Add JARs...

[4] lib > ojdbc8.jar > OK > Apply and Close

[5] Referenced Libraries 확인 시, ojdbc8.jar 추가 완료

🙋‍ 잠깐 ! Oracle JDBC Driver는,
프로젝트를 생성할 때마다 반드시 setting 해줘야함 !

  • 위 순서대로 꼭 lib 폴더에 ojdbc8.jar 파일 삽입
  • Classpath에 ojdbc8.jar 파일 추가

👀 Connection

💁‍♀️ Connection이란,
DB와 연결성을 갖는 인터페이스
createStatement()

👉 데이터 베이스(DB)와 연동하는 코드

💁‍♀️ .properties 파일에서 설정 정보를 읽어와 connection을 생성하는 코드 작성

◼ jdbc-config.properties File

driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
user=C##EMPLOYEE
password=EMPLOYEE

📌 Ref. 생성한 jdbc-config.properties 파일을 config 소스폴더 안에 넣기

[1] 해당 프로젝트 우클릭 > New > Source Folder

[2] Folder name에 'config' 입력 후 Finish

[3] 생성한 jdbc-config.properties 파일, config 소스폴더로 복사 완료

◼ Application Class

[1] Properties 객체 생성
Properties prop = new Properties();
[2] DB 접속을 위한 Connection 객체 생성 (추후에 finally 블럭에서 사용하기 위해 try 블럭 밖에 미리 레퍼런스 변수를 선언)
Connection conn = null;
[3] try문 안에서 입력스트림 및 읽어올 Properties 파일경로 전달

load()

try {
	prop.load(new FileReader("src/com/greedy/section01/connection/jdbc-config.properties"));
[4] .properties 파일에서 설정 정보를 읽어오는 코드 작성

getProperty()

	String driver = prop.getProperty("driver");
	String url = prop.getProperty("url");
	String user = prop.getProperty("user");
	String password = prop.getProperty("password");
[5] 사용할 드라이버 등록

forName()

	Class.forName(driver); // (forName의 소괄호 안에 문자열을 넣어줌)
[6] DriverManager를 이용해 Connection 객체 생성

getConnection()

	conn = DriverManager.getConnection(url, user, password); 	
    >>> conn이라는 레퍼런스 변수로 반환 받음 
			
	System.out.println(conn); // oracle.jdbc.driver.T4CConnection@3daa422a
[7] catch문으로 Exception 처리
} catch (IOException e) {
	e.printStackTrace();
} catch (ClassNotFoundException e) {
	>>> 드라이버 클래스명에 오타가 있거나 라이브러리가 추가되지 않았을 경우,
	>>> 해당 클래스를 찾지 못 했다는 exception 발생 가능성
	e.printStackTrace();
} catch (SQLException e) {
	>>> url, user, password 등이 올바르게 입력되지 않아서 연결 할 수 없으면
	>>> exception 발생 가능성
	e.printStackTrace();
[8] conn이 null이 아니라면 닫아주는 finally 구문 생성
} finally {
	if(conn != null) {
		try {
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
} 

👉 JDBCTemplate Class 생성

💁‍ 데이터 베이스(DB)와 연동할 때마다 위의 코드를 계속 작성하는 것은 그다지 효율적이지 못 하므로 DB와 연동시키는 메소드자원을 반납하는 메소드가 담긴 클래스(템플릿)를 생성

◼ getConnection() Method

  • Connection을 return 시켜주는 메소드 (DB와 연동할 때마다 호출 예정)
public static Connection getConnection() {
		
	Connection conn = null;
	Properties prop = new Properties(); // : Properties 객체로부터 파일 읽어오기
		
	try {
		prop.load(new FileReader("config/jdbc-config.properties"));
		
        // properties 파일에서 설정 정보를 읽어오는 코드
		String driver = prop.getProperty("driver");
		String url = prop.getProperty("url");
			
		Class.forName(driver);
		
        // url과 prop만 전달하는 getConnection() 메소드 호출
		conn = DriverManager.getConnection(url, prop);
		>>> Properties안에 있는 값을 전달하기 때문에,
        >>> user와 password를 위에서 따로 입력하지 않아도 OK
			
	} catch (IOException e) {
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	} catch (SQLException e) {
		e.printStackTrace();
	} 
		
	return conn;
    >>> 생성된 Connection을 값으로 반환
}

📌 Ref.

* getConnection(url, prop)
  url과 prop만 전달하는 getConnection() 메소드 호출 시, 계정 정보는 Properties 객체로 
  받기 때문에 user와 password는 따로 정보를 읽어오는 코드를 작성 하지 않아도 됨 

◼ close(Connection conn) Method

  • Connection을 close할 메소드
	public static void close(Connection conn) {
		try {
			if(conn != null && !conn.isClosed()) { // : conn이 null이 아니고 닫히지 않았을 경우,
				conn.close(); // : 닫는다
				
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

◼ close(Statement stmt) Method

  • Statement를 close할 메소드
	public static void close(Statement stmt) {
		try {
			if(stmt != null && !stmt.isClosed()) {
				stmt.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

◼ close(ResultSet rset) Method

  • ResultSet을 close할 메소드
	public static void close(ResultSet rset) {
		try {
			if(rset != null && !rset.isClosed()) {
				rset.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

👉 JDBCTemplate의 메소드 호출

◼ Application Class

import java.sql.Connection;

import static com.greedy.section02.template.JDBCTemplate.getConnection; 
>>> import구문을 따로 작성하면 static 메소드를 Connection conn = getConnection(); 만으로 호출 가능

import static com.greedy.section02.template.JDBCTemplate.close; 

//import static com.greedy.section02.template.JDBCTemplate.*; 
>>> 바로 위에 있는 두 개의 구문을 한꺼번에 import한 것 (*은 그 클래스에 있는 모든 메소드를 의미)

public class Application {

	public static void main(String[] args) {
		
		// getConnection() 메소드 호출
//		/* 방법 1 */ Connection conn = JDBCTemplate.getConnection();
		>>> getConnection() 메소드를 static으로 선언했기 때문에 JDBCTemplate(클래스명)을 명시해야함
		
		/* 방법 2 */ Connection conn = getConnection(); 
        >>> static을 붙여 위에 import해주면 클래스명 없이도 메소드를 호출할 수 있음
		
		System.out.println(conn); // oracle.jdbc.driver.T4CConnection@31c88ec8
		
		// close() 메소드 호출
		close(conn); 
        >>> close()메소드에 이 Connection을 전달하면서 close
	}
}

👀 Statement

💁‍♀️ Statement란,
SQL문을 저장하고 실행하는 기능을 하는 용도의 인터페이스
executeQuery()


💁‍♀️ ResultSet이란,
SELECT 결과 집합을 반환 받을 용도의 인터페이스
next() getString() getInt() getDouble() getDate() ...

🙋‍ 잠깐 ! 새 프로젝트 생성 시, 이렇게 기본적으로 setting ! 🔥중요🔥

  • common 폴더에 JDBCTemplate 클래스
  • config 소스폴더에 .properties 파일
  • lib 폴더에 ojdbc8.jar 파일 삽입 후, Classpath에 ojdbc8.jar 파일 추가

👉 SQL의 EMPLOYEE 테이블에서 컬럼값 반환받기

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import static com.greedy.common.JDBCTemplate.*;
>>> *로 모든 메소드 한꺼번에 import
>>> static import 구문은 직접 작성해야함 (ctrl + space 이용)

public class Application1 {

	public static void main(String[] args) {
		
		>>> DB와의 연동은 항상 Connection부터 시작 !!
        // 만들어둔 getConnection() 메소드 사용
		Connection conn = getConnection();
		
		// 쿼리문을 저장하고 실행하는 기능을 하는 용도의 인터페이스 (.sql로 import)
		Statement stmt = null; 
		// SELECT 결과 집합을 반환 받을 용도의 인터페이스 (.sql로 import)
		ResultSet rset = null;
		
		try {
			// Connection 인스턴스를 통해 Statement 인스턴스 생성
			stmt = conn.createStatement();
			
			// 문자열로 전달한 sql 구문을 실행하고 실행 결과를 ResultSet 타입으로 반환
			rset = stmt.executeQuery("SELECT EMP_ID, EMP_NAME FROM EMPLOYEE"); 
            >>> executeQuery() : 실행하고 싶은 sql구문을 소괄호 안에 문자열로 전달
			
			// 결과 집합에서 다음 행이 존재하는지를 반복문의 조건으로 작성 (값 꺼내오기) 
			while(rset.next()) {
				>>> 커서가 가리키는 행에서 인자로 전달한 컬럼명의 데이터를 요청 메소드 타입의 값으로 반환
				System.out.println(rset.getString("EMP_ID") + ", " + rset.getString("EMP_NAME"));
			}						>>> getString() : 문자열로 반환 받을 것
			
		} catch (SQLException e) {
			e.printStackTrace();
			
		} finally { 
			// 사용했던 모든 자원을 반납
			close(rset);
			close(stmt);
			close(conn);
		}
	}
}

👉 SQL에서 값 반환받는 과정 총 정리

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import static com.greedy.common.JDBCTemplate.*;

public class Application2 {

	public static void main(String[] args) {
		
		// [1] Connection 생성
		Connection conn = getConnection();
		
		Statement stmt = null;
		
		ResultSet rset = null;
		
		try {
			// [2] Statement 생성
			stmt = conn.createStatement();
			
			String empId = "207";
			String query = "SELECT EMP_ID, EMP_NAME FROM EMPLOYEE WHERE EMP_ID = '"+ empId + "'"
			
			// [3] executeQuery()로 쿼리문 실행하고 결과를 ResultSet으로 반환
			rset = stmt.executeQuery(query);
			
			// [4] ResultSet(rset)에 담긴 결과 값을 컬럼 이름 or 인덱스를 이용해서 꺼내오기
			if(rset.next()) {
				System.out.println(rset.getString(1) + ", " + rset.getString(2));
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			// [5] 사용한 자원 반납
			close(rset);
			close(stmt);
			close(conn);
		}
	}
}

👉 EmployeeDTO를 이용하여 Java에 SQL 데이터 옮겨담기

◼ EmployeeDTO Class

import java.sql.Date;

public class EmployeeDTO {

	/* EMPLOYEE 테이블의 컬럼명과 자료형에 기반하여 필드로 작성 */
	private String empId;
	private String empName;
	private String empNo;
	private String email;
	private String phone;
	private String deptCode;
	private String jobCode;
	private String salLevel;
	private int salary;
	private double bonus;
	private String managerId;
	private java.sql.Date hireDate;
	private java.sql.Date entDate;
	private String entYn;
	
	/* 생성자 */
	public EmployeeDTO() {}

	public EmployeeDTO(String empId, String empName, String empNo, String email, String phone, String deptCode,
			String jobCode, String salLevel, int salary, double bonus, String managerId, Date hireDate, Date entDate,
			String entYn) {
		super();
		this.empId = empId;
		this.empName = empName;
		this.empNo = empNo;
		this.email = email;
		this.phone = phone;
		this.deptCode = deptCode;
		this.jobCode = jobCode;
		this.salLevel = salLevel;
		this.salary = salary;
		this.bonus = bonus;
		this.managerId = managerId;
		this.hireDate = hireDate;
		this.entDate = entDate;
		this.entYn = entYn;
	}

	/* getter & setter */
	public String getEmpId() {
		return empId;
	}

	public void setEmpId(String empId) {
		this.empId = empId;
	}

	public String getEmpName() {
		return empName;
	}

	public void setEmpName(String empName) {
		this.empName = empName;
	}

	public String getEmpNo() {
		return empNo;
	}

	public void setEmpNo(String empNo) {
		this.empNo = empNo;
	}

	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 getDeptCode() {
		return deptCode;
	}

	public void setDeptCode(String deptCode) {
		this.deptCode = deptCode;
	}

	public String getJobCode() {
		return jobCode;
	}

	public void setJobCode(String jobCode) {
		this.jobCode = jobCode;
	}

	public String getSalLevel() {
		return salLevel;
	}

	public void setSalLevel(String salLevel) {
		this.salLevel = salLevel;
	}

	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}

	public double getBonus() {
		return bonus;
	}

	public void setBonus(double bonus) {
		this.bonus = bonus;
	}

	public String getManagerId() {
		return managerId;
	}

	public void setManagerId(String managerId) {
		this.managerId = managerId;
	}

	public java.sql.Date getHireDate() {
		return hireDate;
	}

	public void setHireDate(java.sql.Date hireDate) {
		this.hireDate = hireDate;
	}

	public java.sql.Date getEntDate() {
		return entDate;
	}

	public void setEntDate(java.sql.Date entDate) {
		this.entDate = entDate;
	}

	public String getEntYn() {
		return entYn;
	}

	public void setEntYn(String entYn) {
		this.entYn = entYn;
	}

	/* toString */
	@Override
	public String toString() {
		return "EmployeeDTO [empId=" + empId + ", empName=" + empName + ", empNo=" + empNo + ", email=" + email
				+ ", phone=" + phone + ", deptCode=" + deptCode + ", jobCode=" + jobCode + ", salLevel=" + salLevel
				+ ", salary=" + salary + ", bonus=" + bonus + ", managerId=" + managerId + ", hireDate=" + hireDate
				+ ", entDate=" + entDate + ", entYn=" + entYn + "]";
	}
}

◼ Application Class

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

import static com.greedy.common.JDBCTemplate.*;

import com.greedy.model.dto.EmployeeDTO;

public class Application4 {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		System.out.println("사번 입력 받아 해당 사원 조회하기");
		System.out.print("조회하려는 사번을 입력해주세요 : ");
		String empId = sc.nextLine();
		
		// [1] Connection 생성
		Connection conn = getConnection();
		
		Statement stmt = null;
		
		ResultSet rset = null;
		
        // EmployeeDTO 객체 생성
		EmployeeDTO selectedEmp = null; 
		
		try {
			// [2] Statement 생성
			stmt = conn.createStatement();
			
			String query = "SELECT * FROM EMPLOYEE WHERE EMP_ID = '"+ empId + "'";
            				>>> 홑따옴표 빼먹으면 '단일 인용부를 지정해 주십시오' 오류
                            >>> '=' 빼먹으면 '관계 연산자가 부적합합니다' 오류
			
			// [3] executeQuery()로 쿼리문 실행하고 결과를 ResultSet으로 반환 
			rset = stmt.executeQuery(query);
			
			// [4] ResultSet(rset)에 담긴 결과 값을 컬럼 이름을 이용해서 꺼내오기
			if(rset.next()) {
				selectedEmp = new EmployeeDTO();
				
                >>> rset에 담긴 값을 컬럼 이름으로 꺼낸 뒤, EmployeeDTO의 setter에 저장
                >>> 컬럼명 잘못 작성 시, '부적합한 열 이름' 오류
                selectedEmp.setEmpId(rset.getString("EMP_ID")); 
				selectedEmp.setEmpName(rset.getString("EMP_NAME"));
				selectedEmp.setEmpNo(rset.getString("EMP_NO")); 
				selectedEmp.setEmail(rset.getString("EMAIL"));
				selectedEmp.setPhone(rset.getString("Phone"));
				selectedEmp.setDeptCode(rset.getString("DEPT_CODE")); 
				selectedEmp.setJobCode(rset.getString("JOB_CODE"));
				selectedEmp.setSalLevel(rset.getString("SAL_LEVEL"));
				selectedEmp.setSalary(rset.getInt("SALARY"));
				selectedEmp.setBonus(rset.getDouble("BONUS"));
				selectedEmp.setManagerId(rset.getString("MANAGER_ID"));
				selectedEmp.setHireDate(rset.getDate("HIRE_DATE"));
				selectedEmp.setEntDate(rset.getDate("ENT_DATE"));
				selectedEmp.setEntYn(rset.getString("ENT_YN"));
			} else {
				System.out.println("해당 사번으로 조회되는 사원이 없습니다.");
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			// [5] 사용한 자원 반납 
			close(rset);
			close(stmt);
			close(conn);
		}
		// 자바에 옮겨 담은 데이터 출력하여 확인
		System.out.println("selectedEmp : " + selectedEmp); 
	}
}

📌 Ref.

* 자원 반납이란, 외부에서 입출력을 통해 받아온 자원을 반납하는 것.
  따라서 EmployeeDTO는 빌려온 자원이 아니므로 반납할 필요X 

👉 EmployeeDTO를 이용하여 SQL 데이터를 ArrayList에 추가하기

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import static com.greedy.common.JDBCTemplate.*;

import com.greedy.model.dto.EmployeeDTO;

public class Application5 {

	public static void main(String[] args) {
		
		String query = "SELECT * FROM EMPLOYEE";
		
		// 한 행의 정보를 담을 EmployeeDTO 
		EmployeeDTO row = null;
		
		// 여러 DTO를 하나의 인스턴스로 묶기 위한 List
		List<EmployeeDTO> empList = null;
		
		Connection conn = getConnection();
		Statement stmt = null;
		ResultSet rset = null;
		
		empList = new ArrayList<>();
		
		try {
			stmt = conn.createStatement();
			rset = stmt.executeQuery(query);
            >>> 반환값에 대한 처리를 rset에 담기
			
			while(rset.next()) {
				row = new EmployeeDTO();
				
				row.setEmpId(rset.getString("EMP_ID")); 
				row.setEmpName(rset.getString("EMP_NAME"));
				row.setEmpNo(rset.getString("EMP_NO"));
				row.setEmail(rset.getString("EMAIL"));
				row.setPhone(rset.getString("Phone"));
				row.setDeptCode(rset.getString("DEPT_CODE")); 
				row.setJobCode(rset.getString("JOB_CODE"));
				row.setSalLevel(rset.getString("SAL_LEVEL"));
				row.setSalary(rset.getInt("SALARY"));
				row.setBonus(rset.getDouble("BONUS"));
				row.setManagerId(rset.getString("MANAGER_ID"));
				row.setHireDate(rset.getDate("HIRE_DATE"));
				row.setEntDate(rset.getDate("ENT_DATE"));
				row.setEntYn(rset.getString("ENT_YN"));
                
                >>> 객체를 만들고 나서 List에 담아야하므로, 
                >>> empList = new ArrayList<>(); 위에 작성
			
				empList.add(row);
                >>> row 객체가 empList라는 ArrayList에 추가될 것 
                >>> (while문을 통해 값이 없을 때까지)
			}			
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			close(rset);
			close(stmt);
			close(conn);
		}	
		
		// for-each문으로 리스트 값 뽑아오기
		for(EmployeeDTO emp : empList) { 
			System.out.println(emp);
		}
	}
}

👀 PreparedStatement

💁‍♀️ PreparedStatement란,
Statement를 상속받은 인터페이스로써 Statement와 동일한 기능인 쿼리문을 저장하고 동작시킴

  • 하지만, Statement와는 달리, SQLInjection을 막아주는 등의 내부적으로 SQL문을 처리해주는 기능을 더 가지고 있어 Statement보다 더 자주 사용됨

👉 PreparedStatement의 사용

import static com.greedy.common.JDBCTemplate.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Application1 {

	public static void main(String[] args) {
		
		Connection conn = getConnection();
		PreparedStatement pstmt = null;
		ResultSet rset = null;
		
		try {
			>>> PreparedStatement 객체는 생성 시에 sql 구문을 미리 전달
			pstmt = conn.prepareStatement("SELECT EMP_ID, EMP_NAME FROM EMPLOYEE");
			
			>>> 쿼리 실행을 요청할 때는 sql 구문을 전달 X
            >>> 위에서 이미 전달했으므로 전달할 인자(문자열) X
			rset = pstmt.executeQuery();  
			
			while(rset.next()) {
				System.out.println(rset.getString("EMP_ID") + ", " + rset.getString("EMP_NAME"));
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			close(rset);
			close(pstmt);	>>> PreparedStatement는 Statement의 후손이므로 다형성을 적용하여 
          					>>> Statement를 close할 때 사용했던 메소드 그대로 사용 가능
			close(conn);
		}
	}
}

👉 PreparedStatement의 ?(위치 홀더)사용

import static com.greedy.common.JDBCTemplate.*; 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Application2 {

	public static void main(String[] args) {
		
		Connection conn = getConnection();
		PreparedStatement pstmt = null;
		ResultSet rset = null;
		
        >>> PreparedStatement 객체에 전달할 query문의 조건절은 들어가야 하는 
        >>> 리터럴 값 자리에 ?(위치홀더)로 표시
		String empId = "201"
		String query = "SELECT EMP_ID, EMP_NAME FROM EMPLOYEE WHERE EMP_ID = ?";
        				/*AND EMP_NAME = ? AND SALARY > ?*/ => 이런 식으로 추가 가능 
		>>> ? : 위치 홀더(뭔가의 리터럴 값이 들어갈 공간을 물음표로 자리 잡아둠)
		
		try {
			pstmt = conn.prepareStatement(query);  >>> 미리 만들어둔 query 전달
			
            >>> PreparedStatement 객체 생성 후 ?(위치 홀더)에 들어가야 하는 값을 설정
			>>> 만약 위치 홀더의 개수와 일치하지 않으면,
            >>> 'SQLException : 인덱스에서 누락된 IN 또는 OUT 매개변수:: 1'
			>>> 와 같은 exception이 발생 가능
            
			pstmt.setString(1, empId); // 1 : 위치홀더의 첫 번째 인덱스
			
			rset = pstmt.executeQuery();
			
			if(rset.next()) {
				System.out.println(rset.getString("EMP_ID") + ", " + rset.getString("EMP_NAME"));
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			close(rset);
			close(pstmt);
			close(conn);
		}
	}
}

👉 Statement를 PreparedStatement로 변경하여 코드 작성

// EMPLOYEE 테이블에서 조회할 사원의 이름의 성을 입력 받아 
// 해당 성씨를 가진 사원 정보를 모두 출력

Scanner sc = new Scanner(System.in);
System.out.print("조회할 이름의 성을 입력하세요 : ");
String empName = sc.nextLine();
		
/* 1. Connection 생성 */
Connection conn = getConnection();
PreparedStatement pstmt = null;
ResultSet rset = null;

EmployeeDTO employee = null;
List<EmployeeDTO> empList = null;	>>>  여러 명의 사원의 정보를 저장하고자 List 사용
		
String query = "SELECT * FROM EMPLOYEE WHERE EMP_NAME LIKE ? || '%' "; 
										>>> LIKE 다음에 '김%' 대신 ? || '%' 
										>>> LIKE 연산자를 사용 시 %는 꼭 연결연산자 || 를 사용해야함
try {

	>>> PreparedStatement는 executeQuery가 아닌 prepareStatement에서 쿼리문 전달
	/* 2. PreparedStatement 생성 */
	pstmt = conn.prepareStatement(query);
    // 위치홀더 완성 역할
	pstmt.setString(1, empName); >>> PreparedStatement는 위치홀더가 있는 경우, 값 삽입 해줘야함
    
    /* 3. executeQuery()로 쿼리문 실행하고 결과를 ResultSet으로 반환 */
	rset = pstmt.executeQuery();
			
	empList = new ArrayList<>();
    >>> rset까지 잘 수행되었을 때(ResultSet이 올바르게 불러와졌을 때), 
    >>> empList를 ArrayList를 실행하도록 여기서 ArrayList 객체 생성
    
	/* 4. ResultSet(rset)에 담긴 결과 값을 컬럼 이름을 이용해서 꺼내오기 */						 
	while(rset.next()) {
		employee = new EmployeeDTO();
				
		employee.setEmpId(rset.getString("EMP_ID")); 
		employee.setEmpName(rset.getString("EMP_NAME"));
		employee.setEmpNo(rset.getString("EMP_NO"));
		employee.setEmail(rset.getString("EMAIL"));
		employee.setPhone(rset.getString("Phone"));
		employee.setDeptCode(rset.getString("DEPT_CODE")); 
		employee.setJobCode(rset.getString("JOB_CODE"));
		employee.setSalLevel(rset.getString("SAL_LEVEL"));
		employee.setSalary(rset.getInt("SALARY"));
		employee.setBonus(rset.getDouble("BONUS"));
		employee.setManagerId(rset.getString("MANAGER_ID"));
		employee.setHireDate(rset.getDate("HIRE_DATE"));
		employee.setEntDate(rset.getDate("ENT_DATE"));
		employee.setEntYn(rset.getString("ENT_YN"));
				
		empList.add(employee); //empList(ArrayList)에 조회된 employee 들을 넣음
	}
			
} catch (SQLException e) {
	e.printStackTrace();
} finally {
	close(rset);
	close(pstmt);
	close(conn);	>>> 생성했던 순서의 역순으로 close
}
		
for(EmployeeDTO emp : empList) {
	System.out.println(emp);
}

📌 Ref.

* empList를 try문 밖에 미리 null로 두는 이유
  : 만약 아래의 SQL구문의 조회과정에서 오류가 났을 때 empList가 null이면 조회과정에서 오류가 났다는 근거가 생김

👉 .xml에서 수행할 SQL구문을 읽어와서 처리하는 방법

.xml 파일 만들기

◼ employee-query.xml 파일을 만들기 위한 코드 작성

setProperty()

Properties prop = new Properties();
		
prop.setProperty("keyString", "valueString");
		
try {
	prop.storeToXML(new FileOutputStream("src/com/greedy/section02/preparedStatement/employee-query.xml"), "");
} catch (IOException e) {
	e.printStackTrace();
}

◼ 생성된 employee-query.xml에 쿼리문 작성

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<!--  성으로 직원 조회하는 쿼리 -->
	<entry key="selectEmpByFamilyName">
		SELECT
				E.*
			FROM EMPLOYEE E
			WHERE E.EMP_NAME LIKE ? || '%' 
	</entry>
</properties>

◼ employee-query.xml에서 쿼리문 읽어와서 처리

getProperty()

Scanner sc = new Scanner(System.in);
System.out.print("조회할 이름의 성을 입력하세요 : ");
String empName = sc.nextLine();
		
Connection conn = getConnection();
PreparedStatement pstmt = null;
ResultSet rset = null;

EmployeeDTO employee = null;
List<EmployeeDTO> empList = null; 
												
try {
	/* Properties 파일을 읽어오기 위한 Properties 객체 생성 */
	Properties prop = new Properties(); 
			
	prop.loadFromXML(new FileInputStream("src/com/greedy/section02/preparedStatement/employee-query.xml"));
	>>> IOException 처리 하기 위해 try문 안에서 작성
	>>> prop에 .xml 파일의 entry가 담김
	
    /* getProperty의 소괄호 안에 employee-query.xml 파일의 키값 삽입 */
    /* query에 getProperty로 읽어온 sql문을 저장 */
	String query = prop.getProperty("selectEmpByFamilyName");
	
	>>> 쿼리문을 여기에 직접 쓰지 않아도 파일을 통해 읽어오기 가능 !
	
    /* 아래부터 모두 동일하게 진행 */
	pstmt = conn.prepareStatement(query);
	pstmt.setString(1, empName); 
			
	rset = pstmt.executeQuery();
			
	empList = new ArrayList<>(); 
										 
	while(rset.next()) {
		employee = new EmployeeDTO();
				
		employee.setEmpId(rset.getString("EMP_ID")); 
		employee.setEmpName(rset.getString("EMP_NAME"));
		employee.setEmpNo(rset.getString("EMP_NO"));
		employee.setEmail(rset.getString("EMAIL"));
		employee.setPhone(rset.getString("Phone"));
		employee.setDeptCode(rset.getString("DEPT_CODE")); 
		employee.setJobCode(rset.getString("JOB_CODE"));
		employee.setSalLevel(rset.getString("SAL_LEVEL"));
		employee.setSalary(rset.getInt("SALARY"));
		employee.setBonus(rset.getDouble("BONUS"));
		employee.setManagerId(rset.getString("MANAGER_ID"));
		employee.setHireDate(rset.getDate("HIRE_DATE"));
		employee.setEntDate(rset.getDate("ENT_DATE"));
		employee.setEntYn(rset.getString("ENT_YN"));
				
		empList.add(employee); 
	}
			
} catch (SQLException | IOException e) {
	e.printStackTrace();
} finally {
	close(rset);
	close(pstmt);
	close(conn);
}
		
for(EmployeeDTO emp : empList) {
	System.out.println(emp);
}

profile
Tiny little habits make me

0개의 댓글