day23 - 0825
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);
}
}
}