Luver Duck 2022. 8. 27. 10:49

JDBC (Java Database Connectivity)

Java에서 DB에 접속할 수 있도록 하는 Java의 API(Application Programming Interface)

- Java 애플리케이션에서 DB에 연결할 수 있도록 중간 처리를 수행하는 라이브러리 모음

- SQL문을 실행할 수 있게 해주는 함수 호출 인터페이스

- DBMS의 종류에 관계없이 하나의 JDBC API를 사용하여 DB 작업을 처리 (Driver와 URL만 수정하면 된다)

 

진행 순서

1) 데이터베이스 로그인
2) 구문 준비
3) 구문 전송 및 실행
4) 데이터베이스 로그아웃 (보통 생략)

 

Spring JDBC

Spring에서 제공하는 JDBC(Java Database Connectivity)를 위한 라이브러리

- DriverManagerDataSource : DB 연결을 담당하는 인스턴스를 만드는 클래스

- JdbcTemplate : DB에서 사용하는 SQL문을 전송 및 실행하는 인스턴스를 만드는 클래스

 

0. 준비

1) 라이브러리 준비

- 해당 라이브러리들은 Maven Central Repository에서 검색하여 다운받을 수 있다

Oracle ojdbc8
Spring spring-beans
spring-core
spring-tx
spring-jdbc
기타 commons-logging-1.2

2) lib 폴더 생성

- 해당 Java project상에 lib 폴더를 생성한 후 다운받은 라이브러리를 드래그하여 복사한다

 

3) Build Path 설정 : Build에 필요한 source들을 어디서 가져올 것인지(Path) 지정

- Java project 우클릭 - Build Path - Configure Build Path 선택

 

- Classpath를 선택한 후 Add Jars 선택

 

- 해당 Java project에서 lib 폴더 선택 후 다운받은 라이브러리 등록

 

1) DataManagerDataSource 클래스의 인스턴스 생성 및 설정

- 드라이버 클래스 정보, 접속 정보, 계정 정보, 비밀번호 정보를 설정

DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
dataSource.setUser(사용자아이디);
dataSource.setPassWord(비밀번호);

 

2) JdbcTemplate 클래스의 인스턴스 생성

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

 

3) SQL문 생성

- SQL문 준비

String sql = "insert into fifa(rank, nation, score) values(?, ?, ?)";

- 변수 및 변수 배열 생성

int rank = 7;
String nation = "스페인";
double score = "1690.22";

Object[] param = new Object[] {rank, nation, score};

 

3) SQL문 전송 및 실행 : JdbcTemplate의 update() 메소드

- update() 메소드를 실행하면 실행한 데이터 수(int)가 출력된다

int result = template.update(sql, param);
if(result > 0) {
	System.out.println("등록 완료");
}
else {
	System.out.println("등록 실패");
}

 

전체 코드

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

public class Test01 {
	public static void main(String[] args) {
		
		// 1. DataManagerDataSource 클래스의 인스턴스 생성 및 설정
		// - DriverManagerDataSource 클래스의 인스턴스 생성
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		// - 드라이버 클래스 정보, 접속 정보, 계정 정보, 비밀번호 정보를 설정
		dataSource.setUsername("khacademy");
		dataSource.setPassword("khacademy");
		dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
		dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
		
		// 2. JdbcTemplate 클래스의 인스턴스 생성
		JdbcTemplate template = new JdbcTemplate(dataSource);
		
		// 3. SQL구문 준비
		String sql = "insert into fifa(rank, nation, score) values(?, ?, ?)";

		// 변수 배열 생성
		Object[] param = {no, name, type};

		// 3. SQL문 전송 및 실행
		int result = template.update(sql, param);
		if(result > 0) {
			return "등록 완료";
		}
		else {
			return "등록 실패";
		}
	}
}

 

JdbcUtil 클래스 생성

- DB 로그인을 도와주는 DriverManagerDataSource와 JdbcTemplate 클래스의 인스턴스가 포함된 클래스

- 매번 해당 코드를 입력하기보다는 하나의 클래스로 만들어서 import하기 위함

- JdbcUtil의 getTemplate() 메소드를 통해 JdbcTemplate의 인스턴스를 반환

// Spring Framework의 라이브러리에서 
// JdbcTemplate와 DriverManagerDataSource 클래스를 불러오기(import)
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

public class JdbcUtil {

	// JdbcTemplate 인스턴스를 반환하는 메소드
	public static JdbcTemplate getTemplate() {

		// DriverManagerDataSource의 인스턴스 dataSource 생성 및 세팅
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
		dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
		dataSource.setUserName();
		dataSource.setUserPassword();

		// dataSource를 매개변수로 하여 JdbcTemplate의 인스턴스 생성
		JdbcTemplate template = new JdbcTemplate(dataSource);

		// 생성된 JdbcTemplate의 인스턴스 template을 반환
		return template;
	}
}

 

Eclipse에서 Oracle DB의 CRUD 조작

SQL문 전송 및 실행까지만 하는 경우 : 입력(INSERT), 수정(UPDATE), 삭제(DELETE)

1) JdbcTemplate 클래스의 인스턴스 생성 - JdbcUtil 클래스에서 .getTemplate 메소드 호출

2) SQL문 작성 - 입력(INSERT), 수정(UPDATE), 삭제(DELETE)는 각각 SQL문만 다르게 작성하면 된다

3) SQL문의 물음표 ?(바인딩 변수)에 들어갈 Object 타입의 배열 param 생성

4) JdbcTemplate 클래스의 update 메소드

 

** Object 타입으로 배열을 생성하는 이유

- 자료형에 구애받지 않기 위함

 

입력(INSERT)

ex) FIFA 테이블에 점수(SCORE)와 나라명(NATION)을 입력하여 DB에 데이터 등록(INSERT)

// JdbcUtil 클래스에 있는 JdbcTemplate의 인스턴스를 생성하기 위함
import util.JdbcUtil;
import org.springframework.jdbc.core.JdbcTemplate;

public class Crud {
	public static void main(String[] args) {
		
		// 1. JdbcTemplate 인스턴스 생성 - .getTemplate() 메소드
		JdbcTemplate template = JdbcUtil.getTemplate();

		// 2. SQL문 작성
		String sql = "insert into fifa(score, nation) values(?, ?)";

		// 3. 변수 선언 및 변수 배열 생성
		int score = 1755.35;
		String nation = "아르헨티나";
		Object[] param = new Object[] {score, nation};

		// 3. SQL문 전송 및 실행
		// update() 메소드는 SQL문 실행으로 수정된 행 갯수(int)를 반환
		int result = template.update(sql, param);		
		// 만약 수정된 행 갯수가 하나라도 있다면(0보다 크면) 변경 성공
		if(result > 0) {
			System.out.println("등록 성공");
		}
		// 그렇지 않다면(0이면)
		else {
			System.out.println("등록 실패");
		}
	}
}

 

수정(UPDATE)

ex) FIFA 테이블에서 나라명(NATION)을 입력하여 해당 나라의 점수(SCORE)를 변경(UPDATE)

// JdbcUtil 클래스에 있는 JdbcTemplate의 인스턴스를 생성하기 위함
import util.JdbcUtil;
import org.springframework.jdbc.core.JdbcTemplate;

public class Crud {
	public static void main(String[] args) {
		
		// 1. JdbcTemplate 인스턴스 생성 - .getTemplate() 메소드
		JdbcTemplate template = JdbcUtil.getTemplate();

		// 2. SQL문 작성
		String sql = "update fifa set score = ? where nation = ?";

		// 3. 변수 선언 및 변수 배열 생성
		int score = 1755.35;
		String nation = "아르헨티나";
		Object[] param = new Object[] {score, nation};

		// 3. SQL문 전송 및 실행
		// update() 메소드는 SQL문 실행으로 수정된 행 갯수(int)를 반환
		int result = template.update(sql, param);		
		// 만약 수정된 행 갯수가 하나라도 있다면(0보다 크면) 변경 성공
		if(result > 0) {
			System.out.println("등록 성공");
		}
		// 그렇지 않다면(0이면)
		else {
			System.out.println("등록 실패");
		}
	}
}

 

삭제(DELETE)

ex) FIFA 테이블에서 나라명(NATION)을 입력하여 해당 나라의 데이터를 삭제(DELETE)

// JdbcUtil 클래스에 있는 JdbcTemplate의 인스턴스를 생성하기 위함
import util.JdbcUtil;
import org.springframework.jdbc.core.JdbcTemplate;

public class Crud {
	public static void main(String[] args) {
		
		// 1. JdbcTemplate 인스턴스 생성 - .getTemplate() 메소드
		JdbcTemplate template = JdbcUtil.getTemplate();

		// 2. SQL문 작성
		String sql = "delete fifa where nation = ?";

		// 3. 변수 선언 및 변수 배열 생성
		String nation = "스페인";
		Object[] param = new Object[] {nation};

		// 3. SQL문 전송 및 실행
		// update() 메소드는 SQL문 실행으로 수정된 행 갯수(int)를 반환
		int result = template.update(sql, param);		
		// 만약 수정된 행 갯수가 하나라도 있다면(0보다 크면) 변경 성공
		if(result > 0) {
			System.out.println("등록 성공");
		}
		// 그렇지 않다면(0이면)
		else {
			System.out.println("등록 실패");
		}
	}
}

 

SQL문 전송 및 실행 후 실행 결과(ResultSet)를 전달받는 경우 : 조회(SELECT) 

- SQL문 실행 후 생성되는 행별 데이터(ResultSet)를 mapping해서 특정 타입 객체로 반환하는 RowMapper가 필요하다

- JdbcTemplate의 query() 메소드를 사용한다

 

1) JdbcTemplate 클래스의 인스턴스 생성 - JdbcUtil 클래스에서 .getTemplate 메소드 호출

2) SQL문 작성 

3) SQL문의 물음표 ?(바인딩 변수)에 들어갈 Object 타입의 배열 param 생성 - 전체 조회에서 바인딩 변수는 필요없다

4) RowMapper 클래스의 인스턴스 mapper 생성 - maprow() 메소드 오버라이딩

5) List를 생성하여 JdbcTemplate 클래스의 query() 메소드 실행 결과를 저장 - .query(sql문, mapper, param)

6) 저장된 List의 원소를 출력

 

DTO (Data Transfer Object)

DTO는 계층 간(Controller, View, Business Layer) 데이터 교환을 위한 자바 빈즈(Java Beans)를 의미한다.

DTO는 로직을 가지지 않는 데이터 객체이고 getter/setter 메소드만 가진 클래스를 의미한다.

- 필드

- 기본 생성자

- getter & setter

 

RowMapper<T>

- JdbcTemplate에서 사용하는 인터페이스 (Spring Framework에서 제공)

- SQL문의 결과(ResultSet) 집합의 각 행을 mapping하기 위해 maprow() 메소드를 구현(implement)해야 한다

   (인터페이스의 추상 메소드 오버라이딩)

 

- RowMapper의 메소드 (추상 메소드)

<T> maprow(ResultSet rs, int rowNum) ResultSet을 <T>타입의 객체에 mapping하여 반환

 

ex) DB의 GUEST_BOOK 테이블의 모든 데이터를 조회

 

1. GuestBookDto 생성

- DB로부터 GUEST_BOOK 테이블의 행을 불러올 때 전달받을 객체의 형태를 지정

- 필드와 getter/setter 메소드만 정의해준다

public class CustomerDto {

	// 필드
	int customerNum;
	String customerId;
	String customerTel;
	String customerRegistration;
	String customerPurchase;
	int customerPoint;
	String customerLv;

	// 생성자
	public CustomerDto() {
		super();
	}

	// getter & setter
	public int getCustomerNum() {
		return customerNum;
	}
	public void setCustomerNum(int customerNum) {
		this.customerNum = customerNum;
	}
	public String getCustomerId() {
		return customerId;
	}
	public void setCustomerId(String customerId) {
		this.customerId = customerId;
	}
	public String getCustomerTel() {
		return customerTel;
	}
	public void setCustomerTel(String customerTel) {
		this.customerTel = customerTel;
	}
	public String getCustomerRegistration() {
		return customerRegistration;
	}
	public void setCustomerRegistration(String customerRegistration) {
		this.customerRegistration = customerRegistration;
	}
	public String getCustomerPurchase() {
		return customerPurchase;
	}
	public void setCustomerPurchase(String customerPurchase) {
		this.customerPurchase = customerPurchase;
	}
	public int getCustomerPoint() {
		return customerPoint;
	}
	public void setCustomerPoint(int customerPoint) {
		this.customerPoint = customerPoint;
	}
	public String getCustomerLv() {
		return customerLv;
	}
	public void setCustomerLv(String customerLv) {
		this.customerLv = customerLv;
	}
}

 

2. 조회(SELECT)의 결과를 반환하는 메인 메소드

1) JdbcTemplate 클래스의 인스턴스 생성 - JdbcUtil 클래스에서 .getTemplate 메소드 호출

2) SQL문 작성 

3) SQL문의 물음표 ?(바인딩 변수)에 들어갈 Object 타입의 배열 param 생성

4) RowMapper 클래스의 인스턴스 mapper 생성 - maprow() 메소드 오버라이딩

5) List를 생성하여 JdbcTemplate 클래스의 query() 메소드 실행 결과를 저장 - .query(sql문, mapper, param)

6) 저장된 List의 원소를 출력

 

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import util.JdbcUtil;

public class Select {

	public static void main(String[] args) {
		
		// 1. JdbcTemplate 클래스의 인스턴스 생성 - .getTemplate() 메소드
		JdbcTemplate template = JdbcUtil.getTemplate();
		
		// 2. SQL문 작성
		String sql = "select * from customer order by customer_num asc";

		// 3. 변수 선언 및 변수 배열 생성
		// - 모든 항목을 조회할 것이므로 변수는 필요가 없다

		// 4. RowMapper의 인스턴스 생성
		// RowMapper<T> : ResultSet을 <T> 타입 객체에 mapping하여 반환하는 인터페이스
		// <T> : mapping을 할 객체 타입
		// - 인터페이스는 원래 인스턴스 생성이 불가능하지만 
		//   익명 중첩 클래스로서 메소드 오버라이딩만 해주면 인스턴스 생성이 가능하다
		// - maprow() 메소드를 오버라이딩하여 mapping 방식을 정의한다
		RowMapper<CustomerDto> mapper = new RowMapper<CustomerDto>() {
			// 추상 메소드인 maprow() 오버라이딩
			// 메소드 결과로 GuestBookDto 타입 객체를 반환 (여기서는 c가 반환됨) 
			@Override
			public CustomerDto mapRow(ResultSet rs, int idx) throws SQLException {
				// CustomerDto의 인스턴스 생성
				CustomerDto c = new CustomerDto();

				// 필드 세팅
 				// customer_num 컬럼의 값을 int로 반환하여 CustomerNum에 세팅
				c.setCustomerNum(rs.getInt("customer_num"));

				// customer_num 컬럼의 값을 String로 반환하여 CustomerId에 세팅
				c.setCustomerId(rs.getString("customer_id"));

				// customer_tel 컬럼의 값을 String로 반환하여 CustomerTel에 세팅
				c.setCustomerTel(rs.getString("customer_tel"));

				// customer_registration 컬럼의 값을 String로 반환하여 CustomerRegistration에 세팅
				c.setCustomerRegistration(rs.getString("customer_registration"));

				// customer_purchase 컬럼의 값을 String로 반환하여 CustomerPurchase에 세팅
				c.setCustomerPurchase(rs.getString("customer_purchase"));

				// customer_point 컬럼의 값을 int로 반환하여 CustomerPoint에 세팅
				c.setCustomerPoint(rs.getInt("customer_point"));

				// customer_lv 컬럼의 값을 String로 반환하여 CustomerPurchase에 세팅
				c.setCustomerLv(rs.getString("customer_lv"));

				// 세팅된 인스턴스 c를 반환
				return c;
			}
		};
		
		// 5. SQL문 전송 및 실행 후 그 결과인 CustomerDto 타입의 ResultSET을 List에 저장
		List<CustomerDto> list = template.query(sql, mapper);
		
		// 확인용 출력
		for(CustomerDto c : list) {
			System.out.println(c);
		}
	}
}