JDBC 연동
1. Connect/J - MySQL 제공하는 드라이버 로딩 단계
- Connect/J란 MySQL에 연결하기 위해 MySQL에서 제공하는 드라이버를 마라며, DB벤더에서 제공하는 드라이버들은 Class 들을 묶어 둔 jar 파일 형태
- jar 파일의 라이브러리 path 셋팅 단계
- MySQL Community Downloads (https://dev.mysql.com/downloads/) 에서 Connector/J 다운로드
- Java Build Path -> Libraries -> Add External JARs 로 해당 jar파일 라이브러리 경로 잡아주기
- Class 객체를 리턴하는 forName 메소드를 사용
- 드라이버는 MySQL에 연결할 때 한번만 로딩하면 되기 때문에 생성자 속에 구현하면 됨
// 드라이버를 클래스의 내용으로 읽는 부분
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("드라이버 로딩 성공");
} catch (ClassNotFoundException e){
e.printStackTrace();
}
2. DB 연결
- DB에 연결을 위해 Connection 생성 해야함
- Java.sql 안에 DriverManager 클래스가 존재함
- 해당 클래스에 포함된 메소드 중 getConnection() 메소드를 통해 지정된 주소의 DataBase와 연결할 수 있음.
// getConnection 구현 방법
String url = "jdbc:mysql://127.0.0.1:3306/dbname?serverTimezone=UTC&useUniCode=yes&characterEncoding=UTF-8";
String userId = "root";
String password = "1234";
Connection conn = DriverMaganger.getConnection(url, userId, password);
/*
1) url : DB 접근 요청하려는 주소
ex ) url = jdbc:mysql://127.0.0.1(요청 IP주소):3306(MySQL 설정 포트)/(데이터베이스명)?serverTimezone=UTC&useUniCode=yes&characterEncoding=UTF-8";
2) userId : 접근하려는 DB의 userID
3) password : 접근하려는 DB의 password
*/
3. SQL 실행 준비
- Statement 또는 PreparedStatement는 Connection으로 연결한 객체에 Query 작업을 실행하기 위한 객체
- Statement를 생성하고 사용하기 위해선 반드시 Connection이 먼저 연결되어야 함
- 최근엔 PreparedStaement 객체가 더 많이 사용됨
- Statement 객체의 SQL은 실행될 때마다 서버에서 분석
- PreparedStatement는 한번 분석 후 재사용에 용이
- 차이점 더 자세히...(https://webstone.tistory.com/56) 참조 하시면 좋을 듯!!
- PreparedStatement 객체는 Connection 객체의 PreparedStatement() 메소드를 사용해 생성, 메소드의 파라미터로 SQL 문을 담은 String 객체 필요
- 위치홀더(Placeholder)를 사용해 SQL 문장 정의 가능하며 위치 홀더는 ?로 표시하여 사용함
- SQL문 작성한 다음 PreparedStatement 객체를 생성해 매개값으로 sql문 전달
- 위치홀더에 들어갈 값은 PreparedStatement 객체의 setString(), setInt()의 메소드를 통해 셋팅 가능
- ?위치의 인덱스 번호와 셋팅할 값을 맞춰서 넣어주면 됨
// SQL 문 작성 (매개변수로 넘겨줄 String 형태의 sql문)
String sql = "insert into dbname (id, name, price, index)"
sql += "values (?, ?, ?, ?)";
// SQL문 실행 위해 PreparedStatement 객체 생성
PreparedStatement pstmt = conn.preparedStatement(sql);
// 값 세팅
/*
? 안에 들어가는 변수의 형에 따라 setString/setInt/... 등 맞춰주기
setString 첫 번째 매개변수에 들어가는 것은 ?의 인덱스 즉 ?의 순서
*/
pstmt.setString(1, productId);
pstmt.setString(2, productName);
pstmt.setInt(3, productPrice);
pstmt.setString(4, productIdx);
4. SQL 실행
- SQL 실행 위해 PreparedStatement 객체 안의 execute 메소드 활용
- Create(Insert 문) / Update(Update문) / Delete(Delete문) 실행 시 executeUpdate() 메소드 활용
- Read (Select 문) 실행 시 executeQuery() 메소드 사용
- executeQuery() 메소드
- preparedStatement에 셋팅 된 sql문을 실행 후 리턴 값으로 query의 처리 결과가 반환됨
- 즉 row 개수 반환하여 return 값이 int형의 숫자
// SQL문 실행 - preparedstatement 실행
int cnt = pstmt.executeUpdate();
System.out.println(cnt +"개 입력 성공!");
- executeQuery() 메소드
- preparedstatement에 셋팅된 sql문 실행 후 리턴 값으로 조회된 테이블 데이터를 select 형태로 반환
- 즉 return 값이 ResultSet 이므로 ResultSet에 next() 메서드를 활용하면 리턴된 테이블 데이터의 처음부터 데이터가 끝날 때까지 row() 별로 읽어옴
// SQL문 실행 - PrepareStatement 실행
String sql = "select product_id, product_name, product_price, product_desc \n";
sql += "from product";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
// next() 에는 가져온 테이블에 처음 부분으로 올라가는 first() 기능이 포함됨
while(rs.next()){
String p_id = rs.getString("product_id");
String p_name = rs.getString("product_name");
int price = rs.getInt("product_price");
String Pdesc = rs.getString("product_desc");
System.out.println(p_id +" " + p_name +" " +price +" " + Pdesc);
}
5. SQL 연결 끊기
- DB 모두 사용 후 반드시 close() 메소드로 실행해 연결 끊어야 함
- 연결 끊는 순서는 연결했던 반대 순서로 끊기
- DB연결을 종료하지 않으면 쓰레기 값이 남아 오류가 발생할 수 있으므로 주의..!
- 역순으로 끊는 이유는 DB 끊으면 ResultSet이나, Statement에 쓰레기 값이 남을 수 있기 때문임
// 방법 1 -하나씩 모두 확인 후 끊어 주기
public void close(Connection conn, PreparedStatemet pstmt, ResultSet rs) {
try{
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(conn != null) conn.close();
} catch(SQLException e){
e.printStackTrace();
}
}
// 방법 2 - try-with-resources : try() 문에서 선언된 객체들에 대해
// try가 자동 종료될 때 자동으로 자원을 해제해주는 기능을 이용
/**
Connection, PreparedStatement, ResultSet 모두 AutoCloseable을 구현함
AutoCloseable은 try에 선언된 객체가 AutoCloseable을 구현했더라면 java가 try 구문이
종료될 때 자동을 close() 메소드를 해제
**/
try(Connection conn = DBconnection.getConnection();){
String sql = "select product_id, product_name, product_price, product_desc \n";
sql += "from product";
try(PreparedStatement pstmt = conn.preparedStatement(sql);
ResultSet rs = pstmt.executeQuery();){
while (rs.next()) {
String p_id = rs.getString("product_id");
String pname = rs.getString("product_name");
int Price = rs.getInt("product_price");
String Pdesc = rs.getString("product_desc");
System.out.println(p_id + " " + pname + " " + Price + " " + Pdesc);
}
} catch(SQLException e){
e.printStackTrace();
}
} catch(SQLException e){
e.printStackTrace();
}
// 방법 3 - AutoCloseable을 구현한 객체를 가변으로 받는 메소드 만들기
// close(인자1, 인자2, ...)로 넣어서 여러 파일에서 사용 가능
// 가변 인자를 받게 해주는 문법이 사용되므로 JDK 7 이후부터 이용 가능
public static void close(AutoCloseable... autoCloseable){
for(AutoCloseable ac : autoCloseable){
if(ac != null){
try {
ac.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
}