외부 라이브러리 추가도 해보구.. 이클립스에서 뭐라뭐라하면 디비에서 짜잔~!되는 거 신기방기구..
오라클 드라이버 & 라이브러리를 buildPath에 추가
[참고]
- 라이브러리를 만든 업체를 가야 api 문서 볼 수 있음
- .jar: java archive 자바로 만들어진 프로그램
- 모듈패스: 모듈에서만 쓸 수 있음
- 클래스패스: 클래스 전체가 쓸 수 있음
- 프로젝트 만들 때마다 라이브러리 import 필요

데이터베이스 로그인
SQL문 준비
insert into guest_book(no, name, memo)
values(6, '피카츄', '하이');
구문 전송 및 실행
데이터베이스 로그아웃(생략)
//목표: c##academy 계정의 fifa_ranking 테이블에 데이터 insert
//1. 데이터베이스 로그인
//a. 로그인 도구 생성
//SQL Developer에서 접속 설정하는 것을 직접 입력하는 것
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUsername("khacademy");
dataSource.setPassword("khacademy");
dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
//b. 구문 실행 도구 생성
//template은 dataSource를 통해 로그인 정보를, sql을 통해 실행할 구문을 전달받음
JdbcTemplate template = new JdbcTemplate(dataSource);
//2. 구문 준비
//sql 구문을 자바가 sql문으로 알아들을 수 있도록 문자열로 저장
//[주의] 줄바꿈 시 sql문 공백 위치 확인 필요
String sql = "insert into guest_book(no, name, memo) "
+ "values(6, '피카츄', '하이')";
//3. 구문 전송 및 실행
template.update(sql);
//확인용 출력 구문
//System.out.println("완료");

로그인과 구문실행 도구를 생성하는 코드는 매번 같은 내용을 타이핑 해야 함. 다른 클래스에 메소드화해서 언제든 불러낼 수 있도록 하면 전체 코드가 간소화됨
/*
- 접근제한: public
- 객체 없이 사용: static
- 반환형: JdbcTemplate
- JdbcTemplate 타입을 반환해서 DB에 넘겨야 함
- 준비물(매개변수): 변할 수 있는 데이터의 범위에 따라 달라짐(계정 정보, 디비 종류 등)
*/
package util;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class JdbcUtil {
public static JdbcTemplate getTemplate() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUsername("c##academy");
dataSource.setPassword("c##academy");
dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
JdbcTemplate template = new JdbcTemplate(dataSource);
return template;
}
}
main에서 JdbcUtil 메소드 호출(코드 간소화)
JdbcTemplate template = JdbcUtil.getTemplate();
String sql = "";
Object[] param = {};
template.update(sql, param);
정적 바인딩: Object의 타입이 컴파일러에 의해 컴파일 타임에 결정되는 것
문자열 더하기 연산 사용
- String sql 구문에 필요한 데이터를 변수로 치환
//변수
int no = 6;
String name = "피카츄";
String name = "하이";
String sql = "insert into guest_book(no, name, memo) "
+ "values("+ no +", '"+ name +"', '"+ memo"')";
동적 바인딩: Object의 타입이 런타임 중에 결정되는 것
sql문을 미완성으로 작성하고 입력받을 데이터를 ?(플레이스 홀더: 자리 잡는 역할) 처리
배열 생성
[주의] Object[] param 배열 데이터와 위치홀더의 데이터 순서가 같아야 함
String sql = "insert into guest_book(no, name, memo) "
+ "values(?, ?, ?)";
//Object[] param = new Object[] {no, name, memo};
Object[] param = {no, name, memo}; //약식 표현 가능
// 구문 전송 및 실행
template.update(sql, param);

sql 문자열에 update 구문을 대입
수정해야 하는 값을 홀더 처리
String sql = "UPDATE GUEST_BOOK SET NAME = ? MEMO = ? WHERE NO = ?";
Object[] param = {name, memo, no};

int result = template.update(sql, param);
// System.out.println("result = " + result);
if(result > 0) {
System.out.println("변경 성공");
}else {
System.out.println("해당 데이터가 테이블에 없음");
}객체 형태로 변환해서 List로 추출해야 함ResultSet매핑해줘야 함(setter())query() 활용DTO(Data Transfer Object) 클래스 생성
a. 데이터베이스 테이블 안에 있는 한 개의 행 데이터를 저장하기 위한 클래스
b. DB 컬럼을 변수화해서 필드 선언
c. getter & setter, 생성자, 출력용 toString() 생성
d. SQL 쿼리에서도 WHERE절로 조건을 설정하기는 하나, setter에도 조건을 설정하면 더 확실하게 검증된 데이터만 보유할 수 있음(안전성 향상)
행별 데이터를 복사해서 저장할 DTO 클래스의 객체를 생성
RowMapper 객체 생성(여러 개의 값을 반환받기 위함)
a. ResultSet에서 한 행의 데이터를 읽어와 setter()를 통해 객체에 저장(복사)
b. setter()를 통해 변수와 DB 컬럼을 매핑해줬기 때문에 RowMapper가 이 과정을 대신 처리해줄 수 있음
c. idx(rowNum, 행의 개수)만큼 반복(ResultSet의 행을 알아서 세어줌)
d. [참고] RowMapper는 인터페이스이므로 반드시 추상 메소드 mapRow()를 재정의해야 하는데, 객체를 하나만 만들기 위해 클래스를 추가로 생성하는 것은 비효율적임. 익명 중첩 클래스를 통해 객체를 만들면서 즉석에서 클래스를 구성해 특정 기능을 재정의하는 방식을 사용.
행별 데이터를 하나로 모아서 저장할 List 객체를 생성
SELECT 쿼리 실행 결과를 List에 저장
a. SQL 쿼리에서 ORDER BY로 정렬을 하는 경우에 대비해 순서가 있는 자료구조인 List를 사용
b. query() 인자값으로 sql, RowMapper객체(mapper), 바인딩변수에 세팅될 값(param) 을 설정
List를 통해 원하는 내용을 출력

public class CountryDto {
private int ranking;
private String nation;
private double score;
//getter & setter, 생성자, toString() 생략
}
public class Test01 {
public static void main(String[] args) {
JdbcTemplate template = JdbcUtil.getTemplate();
String sql = "SELECT * FROM FIFA_RANKING"; //(ResultSet)
//테이블을 객체로 변경하는 방법이 작성된 RowMapper 객체를 구현
//객체를 생성하고자 하는 클래스를 제네릭에 작성
RowMapper<CountryDto> mapper = new RowMapper<CountryDto>() {
@Override
//ResultSet을 받아 CountryDto를 만들기
//= rs에 들어있는 데이터를 꺼내서 CountryDto로 복사
public CountryDto mapRow(ResultSet rs, int idx) throws SQLException {
CountryDto dto = new Country();
//rs에는 한 줄의 데이터가 들어있음
//rs에 들어있는 데이터 중 ranking 컬럼의 값을 get(꺼내기)해서 ranking 필드에 주입
dto.setRanking(rs.getInt("ranking"));
dto.setNation(rs.getString("nation"));
dto.setScore(rs.getDouble("score"));
return dto; //rs를 dto로 복사한 결과 반환
}
};
//List<Country> list = template.query(sql, 변경 방법)
List<CountryDto> list = template.query(sql, mapper);
for(CountryDto dto : list) {
System.out.println(dto);
}
}
}
함수형 인터페이스이므로 람다식으로 표현할 수 있음RowMapper<CountryDto> mapper = (rs, idx) -> {
CountryDto dto = new Country();
dto.setRanking(rs.getInt("ranking"));
dto.setNation(rs.getString("nation"));
dto.setScore(rs.getDouble("score"));
return dto;
};