Java CallableStatement

2023. 2. 26. 17:41Java

프로젝트 내 src 내 javabasic 패키지 내 ObjectSerTest.java

//PS C:\Users\ydbon> sqlplus
//
//SQL*Plus: Release 11.2.0.1.0 Production on 수 3월 9 09:44:19 2022
//
//Copyright (c) 1982, 2010, Oracle.  All rights reserved.
//
//사용자명 입력: scott/a1234
//
//다음에 접속됨:
//Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
//With the Partitioning, OLAP, Data Mining and Real Application Testing options
//
//SQL> #객체들을 주고받기위해서는 직렬화과정이필요한데 객체에는 여러가지변수인스턴스들로이루어져있다.
//SP2-0734: "객체들을 ..."(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SQL> #그런멤버를스트림에옮기기위해 하나하나씩 변수들을 나열해서 전송해야 한다.
//SP2-0734: "그런멤버를..."(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SQL> @직렬화된 객체를 데이타베이스에 저장할수있는데 blob필드에 지정할수있다는것이다.
//SP2-0310: 파일 "직렬화된.sql"을 열 수 없습니다.
//SQL> 클래스만들때serializable을...써야한다
//SP2-0734: "클래스만들..."(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SQL> serializable interface를구현해야
//SP2-0734: "serializab..."(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SP2-0044: 명령어 목록을 보려면 HELP를
//빠져나가려면 EXIT를 입력하시오.
//SQL> 오라클칼럼에서 다시 가져오려면 역직렬화과정도거쳐야한다.
//SP2-0734: "오라클칼럼..."(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SQL> create table object_table(
//  2  no number,
//  3  obj_name varchar2(1000),
//  4  obj_value blob default empty_blob()
//  5  );
//
//테이블이 생성되었습니다.
//
//SQL> create sequence object_ser_seq increment by 1 start with 1;
//
//시퀀스가 생성되었습니다.

package javabasic;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

import oracle.sql.BLOB;

public class ObjectSerTest implements java.io.Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	static final String driver_class = "oracle.jdbc.driver.OracleDriver";
	static final String connectionURL = "jdbc:oracle:thin:@localhost:1521:orcl";
	static final String userId = "scott";
	static final String userPassword = "a1234";
	static final String getSequenceSQL = "SELECT object_ser_seq.nextval FROM dual";
	static final String writeObjSQL = "BEGIN" + " INSERT INTO object_table(no, obj_name, obj_value)"
			+ " VALUES(?,?,empty_blob())" + "RETURNING obj_value INTO ?; " + "END;";
	// 위의 프로시저에서 empty_blob()는 굳이 안넣어도 된다
	// returning obj_value into ? 에서 ?부분은 파라미터로 설정해서 처리할것
	// returning obj_value는 obj_value값을 받겠다는 것이다.(물음표)
	// obj_value값으로 받아야되는데 이때 받는 변수는 이제 자바에서 처리해야할 타입으로
	// OutParameter를 설정하겠다는 의미이다.물음표에는 java.sql.types.BLOB
	// 타입으로 요 obj_value값인 empty_blob()값을 받아서 처리하기 위해서
	// registerOutParameter로 등록을 해놓는 것이다.프로시저 문을 실행했을때
	// 그럼 프로시저에서 어떤 변숫값으로 returning obj_value INTO ?에서 물음표가
	// 어떤 변숫값으로 처리가 된다.그 변숫값을 이제 자바에서 받아가지고 처리하기 위해서
	// java.sql.Types 패키지에서 BLOB타입으로 등록을 해놓는 것이다.프로시저에서 받는
	// 값을 자바에서 처리하겠다.registerOutParameter의 의미다.

	// 직렬화된 객체를 불러온다(직렬화된 객체를 저장을 하고 그 저장된 객체를 다시 불러온다.)
	static final String readObjSQL = "SELECT obj_value FROM object_table WHERE no = ?";

	// 직렬화된 객체를 write하는 메서드,저장한객체의넘버값을반환한다
	public static long writeObj(Connection conn, Object obj) throws Exception {
		long rec_key = getNextSeqVal(conn);// 시퀀스얻어와서 설정하기
		String className = obj.getClass().getName();
		CallableStatement stmt = conn.prepareCall(writeObjSQL);

		stmt.setLong(1, rec_key);
		stmt.setString(2, className);
		stmt.registerOutParameter(3, java.sql.Types.BLOB);
		stmt.executeUpdate();

		// BLOB는 오라클사객체이다
		BLOB blob = (BLOB) stmt.getBlob(3);// obj_value의 blob타입을 얻어온다
		// 스트림객체를 생성하기,blob와 연결되어 있는 아웃풋스트림이다.
		// 이런 스트림을 노드스트림이라고 한다.직접 blob와 연결되어있는 아웃풋스트림이기
		// 때문이다.실제 blob에 연결되어 있는 스트림이다.
		@SuppressWarnings("deprecation")
		OutputStream out = blob.getBinaryOutputStream();
		// 아웃풋스트림을 직렬화를 한다.직렬화하는 오브젝트아웃풋스트림을생성해줘야한다
		// 직렬화하는 아웃풋스트림
		// 노드를 연결하기 위한 브릿지 역할하는 브릿지 스트림역할이다.
		ObjectOutputStream oop = new ObjectOutputStream(out);// OutputStream과 연결해서 사용한다.
		// 직렬화
		oop.writeObject(obj);
		oop.flush();
		oop.close();
		out.close();
		stmt.close();
		System.out.println("직렬화 완료!!!" + className);

		return rec_key;
	}

	// 직렬화된 객체가 실지 데이타베이스에 저장되는데 이저장되어있는객체를 역으로
	// 역직렬화를 시키는 방법. 저장되어있는객체를 반대로 객체화 하는 과정이다.
	// 디비에 저장된 객체를 불러오는 read 메소드
	public static Object readObj(Connection conn, long rec_key) throws Exception {
		PreparedStatement stmt = conn.prepareStatement(readObjSQL);
		// 요 해당 rec_key값은 write한후 돌려받은 키값이 된다.이부분은메인에서처리.
		stmt.setLong(1, rec_key);
		// 수행
		ResultSet rs = stmt.executeQuery();
		rs.next();// blob객체이므로 blob 객체 스트림을 통해서 얻어오면 되겠다.

		// InputStream을 통해서 getBlob에있는 내용을 읽어올수가 있는거죠.
		// InputStream 자체가 노드스트림이잖아요.직접 blob로부터연결되있기땜에
		// 이 노드스트림을 다시 역직렬화하기위해서는 오브젝트인풋스트림(역직렬화)이 필요하다
		InputStream is = rs.getBlob(1).getBinaryStream();// obj_value한개 blob객체의스트림
		// 그런데 역직렬화를 통해서 얻어와야 한다.
		// ObjectInputStream은 브릿지역할을해준다.is객체를이용해서 브릿지역할해
		// 줘야해요.그래야 역직렬화를할수있는것을생성한다.
		ObjectInputStream oip = new ObjectInputStream(is);

		Object obj = oip.readObject();

		// 클래스이름을 구해와서 역직렬화가 제대로 되었는지 확인한다
		String className = obj.getClass().getName();
		oip.close();
		is.close();
		if (rs != null)
			rs.close();
		if (stmt != null)
			stmt.close();
		System.out.println("역직렬화 완료!! " + className);

		return obj;
	}

	// next sequence를 구하는 메소드,sequence의 다음값을 구한다
	private static long getNextSeqVal(Connection conn) throws Exception {

		Statement stmt = conn.createStatement();
		ResultSet rs = stmt.executeQuery(getSequenceSQL);
		rs.next();// nextValue값에 커서를 위치시키고 그걸 구해온다.
		long rec_key = rs.getLong(1);// 가져온값은nextVal 하나뿐이므로.
		if (rs != null)
			rs.close();
		if (stmt != null)
			stmt.close();
		return rec_key;
	}

	// 메인 메소드
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub

		Connection conn = null;

		System.out.println("JDBC 드라이버 로딩 ->" + driver_class);
		Class.forName(driver_class);

		// 데이타베이스 연결접속
		System.out.println("데이타 베이스 접속 -> " + connectionURL);
		conn = DriverManager.getConnection(connectionURL, userId, userPassword);
		System.out.println("접속 계정 : " + userId);

		conn.setAutoCommit(false);

		// 직렬화가능한 클래스의 인스턴스 생성
		ObjectSerTest obj = new ObjectSerTest();
		// 객체를 직렬화해서 데이타베이스에 쓰는 과정이 필요하다(직렬화가 가능한 오브젝트를 사용해야 한다)

		// 직렬화된 객체를 oracle blob 컬럼(필드)에 저장
		long rec_key = writeObj(conn, obj);
		conn.commit();

		System.out.println("직렬화된 객체의 번호 ->" + rec_key + "\n");

		System.out.println("객체의 값 ->" + readObj(conn, rec_key));

		if (conn != null)
			conn.close();
	}// main

}
//SQL> select * from object_table;
//
//NO
//----------
//OBJ_NAME
//--------------------------------------------------------------------------------
//OBJ_VALUE
//--------------------------------------------------------------------------------
// 1
//jdbc_prg.ObjectSerTest
//ACED0005737200166A6462635F7072672E4F626A65637453657254657374375076BCD97D00750200
//007870
//
//22
//javabasic.ObjectSerTest
//
//NO
//----------
//OBJ_NAME
//--------------------------------------------------------------------------------
//OBJ_VALUE
//--------------------------------------------------------------------------------
//ACED0005737200176A61766162617369632E4F626A6563745365725465737471DC7119B914F01E02
//00007870
//
//24
//javabasic.ObjectSerTest
//ACED0005737200176A61766162617369632E4F626A65637453657254657374000000000000000102
//00007870
//
//NO
//----------
//OBJ_NAME
//--------------------------------------------------------------------------------
//OBJ_VALUE
//--------------------------------------------------------------------------------
//SQL> #16진수binary형태로 blob타입으로 저장이 된것

실행 결과

JDBC 드라이버 로딩 ->oracle.jdbc.driver.OracleDriver
데이타 베이스 접속 -> jdbc:oracle:thin:@localhost:1521:orcl
접속 계정 : scott
직렬화 완료!!!javabasic.ObjectSerTest
직렬화된 객체의 번호 ->24

역직렬화 완료!! javabasic.ObjectSerTest
객체의 값 ->javabasic.ObjectSerTest@49993335

 

 

java.sql.CallableStatement

CallableStatement 는 인터페이스 (규격) 로써 SQL에서 저장된 절차들을 실행하는데에 사용된다.

JDBC API 는 한개의 저장된 절차에 SQL escape(벗어나는 수단, 탈출) 구문을 제공하는데 그러한 탈출 구문은 모든 RDBMS들에서 저장된 절차들이 표준적인 방법으로 호출되어지는 것을 허용한다.

요 탈출 구문은 한개의 결과 파라메터를 포함하는 형식과 포함하지 않는 형식을 가진다.

만약에 사용된다면, 고 결과 파라메터는 반드시 OUT 파라메터(인수)로 등록되어져야만 한다.

다른 파라메터들(인수들)은 입력, 출력, 또는 입출력 둘다로 사용될 수 있다.

IN 파라메터 값들은 PreparedStatement 로부터 이어받은 set 메서드를 이용하면서 설정된다. 모든 OUT 파라메터들의 유형(모양)은 반드시 저장된 절차를 실행하기 전에 등록되어져야만 한다; OUT 파라메터들(인수들)의 값들은 여기서 제공된 get 메서드들을 통해 실행 후에 정보가 끌어내어진다.

 

'Java' 카테고리의 다른 글

Java - java.sql  (0) 2023.02.27
Java CharArrayReader class  (0) 2023.02.27
Java executeBatch()  (0) 2023.02.26
Java ResultSetMetaData  (0) 2023.02.24
Java Collections class  (0) 2023.02.21