21-JDBC
JDBC
sql는 데이터 접근을 가능하게 하는 기능 언어일 뿐이다. 예를 들어 회원가입을 해야한다면, db에 저장하고 create tabl/ insert 키보드 입력해야 한다면, sql만으로는 불가능하고 자바언어에서 db 이용이 가능하게 하는 라이브러리 모음이 필요하다. 그것이 JDBC(Java Database Connectivity)
- 자바언어의 특성상 소스코드를 한 번 작성하면 동일하게 실행되고, 따라서 jdbc소스를 한 번 작성하면 모든 db이용이 가능하다. 즉 db독립적 형태 유지가 가능하다.
DB 연결
자바 프로그램 내에는 다음과 같은 인터페이스가 내장되어 있어, sql db연결이 가능하다.
-
DB종류마다 (표준SQL 독자적SQL 데이터 타입 등) 다르며, 데이터베이스마다 연결하는 방법 또한 다 다르다.
-
database에서 commit을 하지 않을 시 jdbc는 대기 중, 실행되지 않는다. jdbc는 자동 commit
api - java.sql.* (java.sql.인터페이스)
interface Connection {
void connect();
}
class OracleConnection implements Connection{
public void connect(){ oracle db 연결 라이브러리 호출 }
}
eclipse - SQL 연결
- oracle의 objbc6.jar(버전에 따라 다름)를 사용 jdk 경로 jre/lib/ext 안에 이동시킨다. 그리고 이클립스를 재시작.
- 여러개의 자바 클래스 파일들이 모여있는 라이브러리 소프트웨어 패키지 파일 포맷인 JAR(Java Archive)를 사용함으로써, SQL과 관련된 명령어로 데이터 송출 및 조회가 가능해진다.
JAVA eclipse 내에서 DB를 연동
순서: 1. Connection -> 2. Statement -> 3. Result or Update -> 4. Close
-
JDBC driver (자바클래스) 등록 메모리 로드
Class.forName ( "oracle.jdbc.driver.OracleDriver");
- oracle.jdbc.driver.OracleDriver: objbc6.jar 내부에 포함되어 있는 메소드 이름
-
- db 연결
-
db 독립적 통일 호출
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe", "hr", "hr")
- @127.0.0.1:1521 는 서버 ip를 의미한다. 127.0.0.1:1521(=localhost)은 어느 컴퓨터도 상관 없이 자신의 컴퓨터를 가르킨다. 내 컴퓨터 내부의 SQL을 사용하겠다는 것.
- 후에 한 대의 db를 사용해서 공유한다면, db가 설치되어있는 ip로 지정하면 됨.
- xe 는 버전을 의미(정해져있음)
- “hr”, “hr” = “계정 이름”,”계정 비밀번호” : 해당 계정에 접속한다.
-
SQL전송
SQL 전송시, createStatement, preparedStatement 두 가지 객체를 사용할 수 있다.
Interface인 Statement는 SQL을 전송하는 역할을 한다.
-
createStatement와 preparedStatement
PreparedStatement는 Statement를 상속받는 형태를 갖고 있다. interface PreparedStatement extends Statement{ executeQuery(); // 공통 executeUpdate(); // 공통 setInt/setDouble/setString/setDate 등이 Prepared에 추가되어 있음. }
1) createStatement
- insert
-
insert delete update 실행 시 Statement 인터페이스에서 executeUpdate(String sql) 을 사용
-
Statement st = con.createStatement(); //Connection 내의 createStatement 메소드 사용 //실행 st.executeUpdate("insert|update|delete")
String sql = "insert into c_emp values(" + args[0] + ", " + "'" + args[1] + "','" + args[2] +"', " + args[3] + ", " + args[4] + ")"; // : update 실행 시, 변수 결합방식은 +를 사용한다. Statement st = con.createStatement(); int cnt = st.executeUpdate(sql); //excuteUpdate는 행의 개수(int)를 반환한다.
- select
- select 실행 시 Statement 인터페이스에서 executeQuery 사용, executeQuery의 리턴타입은 ResultSet
- ResultSet : 최초 리턴되었을 때 커서가 가리키는 곳은 첫 번째 데이터가 아닌 MetaData 영역이다.
String sql = "select*from c_emp"; //sql을 저장, 전송, 결과를 저장 (그릇에 담기) Statement st = conn.createStatement(); //실행(담은 것을 꺼내서 실행) ResultSet rs = st.executeQuery(sql);
2) PreparedStatement
-
insert
-
Prepared에는 변수를 지정할 필요가 없고, 물음표(?)를 값으로 지정 후 이후 변수값을 지정한다.
String sql = "insert into c_emp values(?, ?, ?, ?, ?)"; PreparedStatement st = conn.prepareStatement(sql); st.setInt(1, 800); st.setString(2, "Emma"); st.setString(3, "Employee"); st.setDouble(4, 1000.0); st.setInt(5, 10);
-
-
select
String sql = "select r, first_name, salary from (select row_number() over(order by salary desc) as r, salary, first_name from employees) where r between ? and ?"; st = conn.prepareStatement(sql); st.setInt(1, Integer.parseInt(args[0])); st.setInt(2, Integer.parseInt(args[1])); rs = st.executeQuery();//executeQuery는 결과(result)를 return.
-
- sql 결과 검색
-
db 연결 해제
tcp 소켓, 파일도 close. db도 반드시 close 처리한다.
ResultSet rs = null; PreparedStatement st = null; Connection conn = null; try{ conn = DriverManager.getConnection rs = st.executeQuery(); st = conn.prepareStatement(sql); }catch(){ }finally{ rs.close(); st.close(); conn.close(); } //순서 주의: ResultSet > Statement > Connection 순서로 close();
다음은 위의 절차로 oracle 의 hr 계정에 연동하고 생성/조회하는 과정이다.
insert
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class PreparedInstertTest {
public static void main(String[] args) {
Connection conn = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");//메모리 로드
conn = DriverManager.getConnection
("jdbc:oracle:thin:@127.0.0.1:1521:xe", "jdbc", "jdbc");//DB호출
System.out.println("db연결성공");
String sql = "insert into c_emp values(?, ?, ?, ?, ?)";
/*값은 나중에 넣어도 되니 형식만 맞추고 변수값은 ?로 제시.
실행 sql 형태를 잡은 상태, 문법 검사 마치고 준비상태 */
PreparedStatement st = conn.prepareStatement(sql);
//? 부분값 세팅 = sql 문장 입력 파라미터값 세팅
st.setInt(1, 800); //1번 ? 변수값 800 입력. oracle에서는 자동 number변경
st.setString(2, "Emma"); //2번 ? 변수값 "Emma"입력. oracle에서는 varchar2로 자동 변경, "" > ''로 변경 (Statement가 변경해줌)
st.setString(3, "Employee");
st.setDouble(4, 1000.0);
st.setInt(5, 10);
//실행
int insertrow = st.executeUpdate();
//이미 검사 마치고 준비상태, sql을 변수값으로 넣으면 다시 ?, ?, ? .. 로 초기화된다. 변수값 x
//리턴결과 검색
System.out.println(insertrow + " 개의 행 삽입");
System.out.println("db연결해제성공");
}catch(ClassNotFoundException e) {
System.out.println("드라이버 세팅 확인");
}catch(SQLException e) {
System.out.println("DB연결 정보 확인");
e.printStackTrace();
}finally {
try {
conn.close();
}catch(SQLException e) { }
}
}
}
select
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;
public class PreparedSelectTest2 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection
("jdbc:oracle:thin:@127.0.0.1:1521:xe", "hr", "hr");
System.out.println("db연결성공");
String sql = "select r, first_name, salary from (select row_number() over(order by salary desc) as r, salary, first_name from employees) where r between ? and ?";
//sql 저장-전송-결과저장 (그릇담기)
st = conn.prepareStatement(sql);
//입력 파라미터값 세팅
st.setInt(1, Integer.parseInt(args[0]));
st.setInt(2, Integer.parseInt(args[1]));
//실행
rs = st.executeQuery();
//리턴결과 검색
while(rs.next()) {
int r = rs.getInt("r");
String emp_name = rs.getString("first_name");
double salary = rs.getDouble("salary");
System.out.println( r + "|" + emp_name + "|" + salary );
}
System.out.println("db연결해제성공");
}catch(ClassNotFoundException e) {
System.out.println("드라이버 세팅 확인");
}catch(SQLException e) {
System.out.println("DB연결 정보 확인");
e.printStackTrace(); // 자세한 원인 출력
}finally {
try {
//순서 주의
rs.close();
st.close();
conn.close();
}catch(SQLException e) { }
}
}
}
그러나 JDBC에서 DDL 실행하는 것은 권고되는 방법이 아니다. 이것은 반드시 db 내부에서 할 수 있도록. 즉, sql 툴 내에서 사용하라. : 사용은 가능하나, 여러개의 jdbc 프로그램이 하나의 table을 작업하면, 충돌이 발생. 보안적으로 좋지 않다.
부가설명
id(int) | name(char) | salary(double) |
---|---|---|
100 | 이자바 | 5000.0 |
rs.next() - true/false : 다음 행에 데이터가 있으면 true, 없으면, false를 return
- 행을 읽어올 때 아래와 같은 구문을 사용한다.
while(rs.next()){ // 다음 행이 존재하는만큼 읽어온다.
rs.getInt(1); // == rs.getInt("id")
rs.getString(2) // == rs.getString("name")
rs.getDouble(3) // == rs.getDouble("salary")
}
Data type | JAVA | ORACLE |
---|---|---|
정수 : rs.getInt() | int | number(n) |
실수 : rs.getDouble() | double | number(n, s) |
문자 : rs.getString() | String | char, varchar2(n); |
날짜 : rs.getDate() | java.sql.Date | date |
rs.getString() | String | to_char(sysdate, ‘yy/mm/dd’) > 문자형 결과 |
DDL (ceate) | jdbc - 자동 commit | run.. - 자동 commit |
---|---|---|
DCL (grant) | jdbc - 자동 commit | run.. - 자동 commit |
DML | jdbc - 자동 commit | run.. - 수동 commit commit or rollback |
DQL = select |