1) Host language에 database commands를 내장
EXEC SQL
가 해당 명령어를 식별EXEC SQL
~ EXEC SQL END DECLARE SECTION
까지는 변수 선언 partint SQLCODE
: SQL code의 state를 return받는 변수:
: binding을 위해 사용2) Database functions library 사용
JDBC Driver Manager: DB와의 연결을 관리
3) Brand-new language 설계
DBMS connection/operation을 위한 Java-based API들의 집합
DriverManager Object
Connection Object
Statement Object
ResultSet Object
DriverManager - url
: IP와 Port # 정보void close()
: resource이기 때문에 사용 후 release가 필요PreparedStatement
: Code template이 고정됨, 매번 Compile할 필요가 없이 파라미터만 수정해주면 되는 형태CallableStatement
: SQL function call을 위해 사용ResultSet - getInt(), getString()
: SQL query 결과의 column의 datatype에 맞는 function을 호출해야 함import java.sql.*; // import JDBC package
public class TestJDBC {
public static final String URL = "jdbc:oracle:thin:@localhost:1521:orcl";
// IP: localhost, Port #: 1521
public static final String USER_UNIVERSITY ="university";
// 연결할 USER
public static final String USER_PASSWD ="comp322";
// USER의 PWD
public static void main(String[] args) throws IOException, SQLException {
Connection conn = null;
Statement stmt = null;
String sql = "";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
// Oracle DBMS를 위해 필요한 JDBC driver load
System.out.println("Driver Loading: Success!");
} catch(ClassNotFoundException e) {
System.err.println("error = " + e.getMessage());
System.exit(1);
}
try {
conn = DriverManager.getConnection(URL, USER_UNIVERSITY, USER_PASSWD);
// Connection을 위해 필요한 정보를 전달해주면서 생성
System.out.println("Oracle Connected.");
} catch(SQLException ex) {
ex.printStackTrace();
System.err.println("Cannot get a connection: " + ex.getLocalizedMessage());
System.err.println("Cannot get a connection: " + ex.getMessage());
System.exit(1);
}
try {
conn.setAutoCommit(false);
// 자동 commit 기능 끄기
stmt = conn.createStatement();
// Connection object로부터 Statement object 받아오기
sql = "DROP TABLE " + TABLE_NAME + " CASCADE CONSTRAINT";
int res = stmt.executeUpdate(sql);
// sql문 실행 (SELECT 이외의 모든 sql은 executeUpdate로 수행)
if (res == 0) System.out.println("Table was successfully dropped.");
StringBuffer sb = new StringBuffer();
sb.append("CREATE TABLE " + TABLE_NAME + " (Id INT, ");
sb.append(" Name VARCHAR2(10), ");
sb.append(" Address VARCHAR2(20))");
sql = sb.toString();
// TABLE 생성을 위한 query문 작성
res = stmt.executeUpdate(sql);
if (res == 0) System.out.println("Table was successfully created.");
conn.commit();
// 자동 commit 기능을 껐으므로 수동으로 commit
} catch(SQLException ex) {
System.err.println("error = " + ex.getMessage());
System.exit(1);
}
try {
sql = "INSERT INTO TEST VALUES (10, 'BAEK', 'Daegu')";
int res = stmt.executeUpdate(sql);
if (res == 0) System.out.println(res + "개의 행이 삽입되었습니다.");
sql = "INSERT INTO TEST VALUES (20, 'KIM', 'Seoul')";
stmt.addBatch(sql);
// 여러 개의 SQL을 한 번에 수행하기 위해 batch에 추가
sql = "INSERT INTO TEST VALUES (30, 'CHOI', 'Busan')";
stmt.addBatch(sql);
sql = "INSERT INTO TEST VALUES (40, 'LEE', 'Jeju')";
stmt.addBatch(sql);
int[] count = stmt.executeBatch();
// batch를 한 번에 수행
System.out.println(count.length + "개의 행이 삽입되었습니다.");
conn.commit();
// 자동 commit 기능을 껐으므로 수동으로 commit
} catch(SQLException ex) {
System.err.println("error = " + ex.getMessage());
System.exit(1);
}
executeBatch()
를 만나면 한 번에 처리한다.try {
sql = "SELECT * from TEST";
ResultSet rs = stmt.executeQuery(sql);
// SELECT는 executeQuery로 수행하고, return되는 결과를 ResultSet에 저장
while (rs.next()) {
// no impedance match in JDBC, rs == null 이면 return된 tuple이 없다는 의미
int id = rs.getInt(1);
String name = rs.getString(2);
String addr = rs.getString(3);
// column index를 전달하여 해당 위치의 value를 return
System.out.println("ID = " + id + ", Name = " + name + ", Address = " + addr);
}
conn.commit();
// 자동 commit 기능을 껐으므로 수동으로 commit
} catch(SQLException ex) {
System.err.println("error = " + ex.getMessage());
System.exit(1);
}
try {
sql = "UPDATE TEST SET Name = 'OH' WHERE Id = 40";
int res = stmt.executeUpdate(sql);
System.out.println(res + "개의 행이 수정되었습니다.");
sql = "DELETE FROM TEST WHERE Id = 30";
stmt.addBatch(sql);
int[] count = stmt.executeBatch();
System.out.println(count.length + "개의 행이 삭제되었습니다.");
// 여러 개의 행이 삭제될 수도 있다.
conn.commit();
// 자동 commit 기능을 껐으므로 수동으로 commit
} catch(SQLException ex) {
System.err.println("error = " + ex.getMessage());
System.exit(1);
}
try {
sql = "SELECT * from TEST WHERE Id = ?";
// ? : parameter를 전달할 부분
PreparedStatement pstmt = conn.prepareStatement(sql);
// query 형태는 고정적이고, 특정 parameter만 변경될 query
pstmt.setInt(1, 40);
// Parameter Setting, 1 : parameter index
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
// no impedance match in JDBC, rs == null 이면 return된 tuple이 없다는 의미
int id = rs.getInt(1);
String name = rs.getString(2);
String addr = rs.getString(3);
// column index를 전달하여 해당 위치의 value를 return
System.out.println("ID = " + id + ", Name = " + name + ", Address = " + addr);
}
conn.commit();
// 자동 commit 기능을 껐으므로 수동으로 commit
rs.close();
pstmt.close();
stmt.close();
conn.close();
// 사용했던 자원 release 필수
} catch(SQLException ex) {
System.err.println("error = " + ex.getMessage());
System.exit(1);
}
SQL은 procedural하지 않았기때문에 위의 특징들이 지원되지 않는다.
모두 block 단위로 처리
DECLARE
section에 명시SET SERVEROUTPUT ON;
DECLARE
vempssn EMPLOYEE.Ssn%TYPE;
vefname EMPLOYEE.Fname%TYPE;
velname EMPLOYEE.Lname%TYPE;
// EMPLOYEE.ATTR와 같은 datatype을 가지도록 설정
// vemp EMPLOYEE%ROWTYPE; : table의 datatype을 가지도록 설정, 즉 table 자체를 참조. 이후 vemp.Ssn, vemp.Lname과 같이 접근 가능
BEGIN
SELECT Ssn, Fname, Lname
INTO vempssn, vefname, velname <- 할당
FROM EMPLOYEE
WHERE Ssn = '888665555';
DBMS_OUTPUT.PUT_LINE(vempssn || ', ' || vefname || ', ' || velname );
END;
/ // PL/SQL statement의 실행을 위해서는 필수
DECLARE
vdname DEPARTMENT.dname%TYPE;
vempssn EMPLOYEE.ssn%TYPE;
vename EMPLOYEE.lname%TYPE;
vsal EMPLOYEE.salary%TYPE;
vlabel VARCHAR2(10);
BEGIN
SELECT dname, ssn, fname || ' ' || lname as ename, salary
INTO vdname, vempssn, vename, vsal
FROM EMPLOYEE e, DEPARTMENT d
WHERE e.dno = d.dnumber and e.ssn = '888665555';
IF (vsal < 20000) THEN
vlabel:='LOW';
ELSIF (vsal < 40000) THEN
vlabel:='MEDIUM 1';
ELSIF (vsal < 60000) THEN
vlabel:='MEDIUM 2';
ELSE
vlabel:='HIGH';
END IF;
DBMS_OUTPUT.PUT_LINE(vdname || ', ' || vempssn || ', ' || vsal || '=>' vlabel);
END;
/ // PL/SQL statement의 실행을 위해서는 필수
COUNTER: 증감하는 변수, REVERSE: 순서 반대로
Implicit cursor
Explicit cursor
query statement의 result를 모두 저장fetch가 더 이상 진행되지 않는 경우 종료하고, CLOSE 단계에서 사용한 메모리 영역을 비움JDBC보다 더 빠른 속도를 보인다.
Cursor와 For LOOP는 잘 결합된다.
PROCEDURE
, FUNCTION
, TRIGGER
포함RETURN
을 통해 결과를 return하거나, 하지 않을 수도 있다.BEGIN-END
사용EXEC stored_procedure_name(...); 로 procedure 호출
// JDBC-Callable Statement로 PSM 사용 가능
DROP PROCEDURE stored_procedure_name; 로 procedure 삭제
---
CREATE OR REPLACE PROCEDURE ComputeAvaSal (
AvgSal OUT NUMBER)
AS
BEGIN
SELECT AVG(Salary) INTO AvgSal
FROM EMPLOYEE;
END;
/
DECLARE
Avgsal NUMBER; -- return 값을 저장할 변수
BEGIN
ComputeAvaSal(Avgsal); -- function처럼 사용 가능
DBMS_OUTPUT.PUT_LINE('Avg. Salary: $' || AvgSal);
END;
/
Procedure
와 다른 점: 어떠한 return 값을 반환Procedure
Trigger
Function