11.24.(금) OracleDB(20): Eclipse+PL/SQL

Eclipse에서 프로시저 실행
DB를 호출하는 방식은 이전과 동일하게 미리 만들어둔 DBConn 클래스를 상속받아서 연결할 예정이다.
마지막으로 생성했던 employee_insert 프로시저를 이클립스에서 실행시켜서 DB에 데이터를 추가해보자.
CREATE OR REPLACE PROCEDURE employee_insert(
i_username IN employee.username%TYPE,
i_password IN employee.password%TYPE,
i_tel IN employee.tel%TYPE,
i_dept_code IN employee.dept_code%TYPE,
i_pos_code IN employee.pos_code%TYPE,
o_result OUT NUMBER) -- insert문 처리결과 내보내기
IS
BEGIN
o_result := 1; -- o_result변수에 1대입
INSERT INTO employee(empno, username, password, tel, dept_code, pos_code)
VALUES (emp_seq.nextval, i_username, i_password, i_tel, i_dept_code, i_pos_code);
-- 예외처리
EXCEPTION
WHEN OTHERS THEN
o_result := 0; -- 예외발생 시 데이터추가 실패
END;
Eclipse에서 DB연결
DB에 데이터를 INSERT하기
package javaJDBCProcedure;
import java.sql.Types;
import java.util.Scanner;
import javaJDBC.DBConn;
public class InsertProcedure extends DBConn{
Scanner sc = new Scanner(System.in);
public InsertProcedure() {}
public void start() {
try {
// 데이터 준비
// 사원명, 비밀번호, 연락처, 부서코드, 직급코드를 입력받아
System.out.print("사원명 : ");
String username = sc.nextLine();
System.out.print("비밀번호 : ");
String password = sc.nextLine();
System.out.print("연락처 : ");
String tel = sc.nextLine();
System.out.print("부서코드 : ");
int dept_code = Integer.parseInt(sc.nextLine());
System.out.print("직급코드 : ");
int pos_code = Integer.parseInt(sc.nextLine());
// 1. 드라이버 로딩 - DBConn 상속하면서 이미 처리됨
// 2. DB연결
dbConn();
// 3. Statement 생성
// 프로시저 호출은 {}내에 표시한다.
sql = "{CALL employee_insert(?,?,?,?,?,?)}";
cstmt = conn.prepareCall(sql);
// 데이터를 statement객체에 할당
cstmt.setString(1, username);
cstmt.setString(2, password);
cstmt.setString(3, tel);
cstmt.setInt(4, dept_code);
cstmt.setInt(5, pos_code);
// 프로시저 처리결과를 out받기 위한 위치에 데이터형을 정의한다
cstmt.registerOutParameter(6, Types.INTEGER);
// 4. 실행
cstmt.executeUpdate();
if(cstmt.getInt(6)>0) { // 사원등록 성공
System.out.println(username + "사원을 등록하였습니다.");
}else { // 사원등록 실패
System.out.println("사원등록을 실패하였습니다.");
}
}catch(Exception e) {
e.printStackTrace();
}finally {
// 5. 종료
dbClose();
}
}
public static void main(String[] args) {
new InsertProcedure().start();
}
}
여기서 주목해야할 점은, 이전과는 달리 PL/SQL의 OUT PARAMETER, 즉 쿼리문의 리턴값을 담아줄 변수를 추가해줘야 한다는 것이다.
입력값은 CallStatement의 setString()과 setInt()를 통해 할당해주면 된다. 하지만 맨 마지막 ?는 OUT PARAMETER이기 때문에,
cstmt.registerOutParameter(int index, data_type);
우리는 java.sql.Types 클래스를 통해서 o_result의 데이터타입을 정해줄 수 있다.
o_result의 데이터타입은 NUMBER이기 때문에, Types.INTEGER로 정했다.
o_result는 employee_insert()프로시저가 데이터입력 성공여부를 알려주는 정수이므로,
0이면 실패, 1이면 성공이라는 조건에 따라 사원등록 성공/실패를 콘솔에 출력시켰다.
DB에서 데이터를 SELECT하기
모든 데이터(사번, 이름, 연락처, 성별, 입사일)를 선택하는 프로시저를 만들자.
SELECT empno, username, tel, startwork FROM employee;
CREATE OR REPLACE PROCEDURE employee_select_all(o_result OUT sys_refcursor)
IS
BEGIN
OPEN o_result FOR
SELECT empno, username, tel, gender, startwork FROM employee ORDER BY empno;
END;
2개 이상의 필드에서 SELECT할때는 커서를 이용해야한다.
커서의 데이터타입은 sys_refcursor이다. 또한 OPEN 커서 FOR으로 어떠한 데이터를 가리킬지 정해준다.
이제 Eclipse로 넘어와서 테이블을 출력해보자.
package javaJDBCProcedure;
import java.sql.ResultSet;
import javaJDBC.DBConn;
import oracle.jdbc.OracleTypes;
public class SelectAllProcedure extends DBConn {
public SelectAllProcedure() {}
public void start() {
try {
dbConn();
sql = "{CALL employee_select_all(?)}";
cstmt = conn.prepareCall(sql);
// ?에 데이터타입 커서를 담을 수 있게 설정
cstmt.registerOutParameter(1, OracleTypes.CURSOR);
cstmt.executeUpdate();
// cstmt에서 ResultSet객체 얻어오기
rs = (ResultSet) cstmt.getObject(1);
// 사번, 이름, 연락처, 성별, 입사일
while(rs.next()) {
System.out.printf("%d\t %s\t %s\t %s\t %s\n",
rs.getInt(1),
rs.getString(2),
rs.getString(3),
rs.getString(4),
rs.getString(5));
}
}catch(Exception e) {
e.printStackTrace();
}finally {
dbClose();
}
}
public static void main(String[] args) {
new SelectAllProcedure().start();
}
}
커서는 java.sql.Types클래스에 없기 때문에 다른 곳에서 import해와야한다. 커서의 데이터형은 Build Path에 추가한 ojdbc.jar라이브러리에 존재한다.
import oracle.jdbc.OracleTypes;
OracleTypes.CURSOR로 OUT PARAMETER에 담아주자.
그리고 쿼리문 실행 이후엔 커서가 가리키는 열의 데이터 집합을 ResultSet rs에 담아주고,
커서가 가리키는게 없을 때 까지 while문으로 하나하나씩 콘솔에 출력해주었다.
데이터 검색하기
이번엔 이름에 특정 알파벳이 있는 사람들만 골라서 SELECT해볼 예정이다.
CREATE OR REPLACE PROCEDURE employee_search(
name_search IN employee.username%TYPE,
r_employee OUT sys_refcursor)
IS
BEGIN
OPEN r_employee FOR
SELECT empno, username, tel, startwork, dept_name, pos_name
FROM employee
JOIN department ON employee.dept_code=department.dept_code
JOIN position ON employee.pos_code=position.pos_code
WHERE username LIKE '%'||name_search||'%'; -- A가 이름에 포함된 사원들
END;
package javaJDBCProcedure;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.ResultSet;
import javaJDBC.DBConn;
import oracle.jdbc.OracleTypes;
public class SelectSearchProcedure extends DBConn{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public SelectSearchProcedure() {
// 이름을 입력받아 해당 사원을 선택하는 프로시저 만들기
// 홍을 입력하면 홍길동을 출력
}
public void start() {
try {
dbConn();
System.out.print("검색할 이름 입력 -> ");
String searchName = br.readLine();
sql = "{CALL employee_search(?,?)}";
cstmt = conn.prepareCall(sql);
cstmt.setString(1, searchName);
cstmt.registerOutParameter(2, OracleTypes.CURSOR);
cstmt.executeUpdate();
rs = (ResultSet)cstmt.getObject(2);
// empno, username, tel, startwork, dept_name, pos_name
while(rs.next()) {
System.out.printf("%d\t %s\t %s\t %s\t %s\t %s\n",
rs.getInt(1),
rs.getString(2),
rs.getString(3),
rs.getString(4),
rs.getString(5),
rs.getString(6));
}
}catch(Exception e) {
e.printStackTrace();
}finally {
dbClose();
}
}
public static void main(String[] args) {
SelectSearchProcedure ssp = new SelectSearchProcedure();
ssp.start();
}
}
employee_select_all()과 거의 비슷하다. BufferedReader로 검색값을 받아서 employee_search()의 입력값으로 넣어줬다.
데이터 UPDATE하기
CREATE OR REPLACE PROCEDURE employee_edit(
i_empno IN employee.empno%TYPE,
i_password IN employee.password%TYPE,
i_tel IN employee.tel%TYPE,
i_endwork IN VARCHAR2, -- yyyymmdd 형식으로 받기
r_data OUT NUMBER)
IS
BEGIN
r_data:=1;
UPDATE employee SET
password=i_password,
tel=i_tel,
endwork=to_date(i_endwork, 'yyyymmdd')
WHERE empno=i_empno;
EXCEPTION
WHEN OTHERS THEN
r_data:=0;
END;
수정 성공 여부를 r_data로 리턴받아서 잘 되었는지 안 되었는지 알 수 있다.
package javaJDBCProcedure;
import java.sql.Types;
import java.util.Scanner;
import javaJDBC.DBConn;
public class UpdateProcedure extends DBConn {
Scanner sc = new Scanner(System.in);
public UpdateProcedure() {
//
}
public void start() {
try {
System.out.print("수정 대상 사원번호 -> ");
int empno = Integer.parseInt(sc.nextLine());
System.out.print("비밀번호 -> ");
String password = sc.nextLine();
System.out.print("새 연락처 (ex.010-1234-5678)-> ");
String tel = sc.nextLine();
System.out.print("퇴사일 (ex.20220425) -> ");
String endwork = sc.nextLine();
dbConn();
sql = "{CALL employee_edit(?,?,?,?,?)}";
cstmt = conn.prepareCall(sql);
cstmt.setInt(1, empno);
cstmt.setString(2, password);
cstmt.setString(3, tel);
cstmt.setString(4, endwork);
cstmt.registerOutParameter(5, Types.INTEGER);
cstmt.executeUpdate();
if(cstmt.getInt(5)>0) {
System.out.println("사원 정보가 수정되었습니다.");
}else {
System.out.println("사원 정보 수정을 실패했습니다.");
}
}catch(Exception e) {
e.printStackTrace();
}finally {
dbClose();
}
}
public static void main(String[] args) {
new UpdateProcedure().start();
}
}
데이터 DELETE하기
CREATE OR REPLACE PROCEDURE employee_del(
i_empno IN NUMBER,
o_result OUT NUMBER)
IS
BEGIN
o_result:=1;
DELETE FROM employee
WHERE empno=i_empno;
EXCEPTION
WHEN OTHERS THEN
o_result:=0;
END;
package javaJDBCProcedure;
import java.sql.Types;
import java.util.Scanner;
import javaJDBC.DBConn;
public class DeleteProcedure extends DBConn {
Scanner sc = new Scanner(System.in);
public DeleteProcedure() {
// 사원번호를 입력받아 해당 사원 삭제하는 프로시저 실행
}
public void start() {
try {
System.out.print("삭제할 사원의 사원번호 -> ");
int empno = Integer.parseInt(sc.nextLine());
dbConn();
sql = "{CALL employee_del(?,?)}";
cstmt = conn.prepareCall(sql);
cstmt.setInt(1, empno);
cstmt.registerOutParameter(2, Types.INTEGER);
cstmt.executeUpdate();
if(cstmt.getInt(2)>0) {
System.out.printf("사원번호 %d 삭제되었습니다.\n", empno);
}else {
System.out.println("사원 삭제를 실패했습니다.");
}
}catch(Exception e) {
e.printStackTrace();
}finally {
dbClose();
}
}
public static void main(String[] args) {
new DeleteProcedure().start();
}
}