*** 배포 자유, 출처 표기 필수 ***
프로토콜 바이올레이션에 대한 자료가 별로 없어 자바 서비스넷의 글들과 제가 올린 답변을 한데 묶어 문서화합니다.
발생원인
첫째, Oracle JDBC Driver의 버젼
오라클 DBMS 버젼이 8.1.X 라면 오라클 JDBC Driver 버젼은 8.1.7.1 을 쓸 것을 권장합니다. 메이저 버젼은 일치시키고 마이너 버젼을 제일 최신의 것을 써주면 좋습니다.
무턱대고 Thin-Driver 9.0.1.0 버젼을 가져다 쓰면 안됩니다.
둘째, JDBC Coding에 있어서 문제
LONG Type의 Data에서 setString(), getString()에서 종종 생깁니다.
셋째, 한글 문자셋 때문에 특정 데이터가 깨져서 특정 Row에만 생기는 문제
이부분은 javaservice.net의 손님(guest)님이 쓴글을 인용하겠습니다.
저도 같은 문제가 생겨서 끙끙거리고 있습니다. 일단 문제를 보니 자바에서 oracle로 데이터를 입출력 할 때에는 ksc5601코드셋으로 변환되어 db쪽으로 들어갑니다. 따라서 특정한 문자... 잌, 샾, 숖 등등의 문자는 깨어져서 들어가지요. 하지만 다시 웹에서 뿌려질 때는 이러한 글자는 정상적으로 출력이 됩니다. 그런데 만약 파워빌더로 짠 프로그램이나 기타 윈도우용 관리 프로그램에서 특정한 문자(위의 ksc5601에서 지원하지 않는 문자)를 입력하게 되면 이문자는 DB로 들어갑니다. 하지만 당영히 깨어져서 들어가겠지요. 그리고 이문자를 윈도우용 프로그램에서 읽으면 정상적으로 읽어집니다. 그러나 JDBC를 이용한 자바에서 이문자를 읽으면 100% violation에러가 발생합니다. 즉, 윈도용 프로그램에서 입력한 문자는 확장완성형 문자이고 DB나 JDBC에서 사용하는 문자셋은 KSC5601이기 때문인 것 같습니다. 아직 JDBC에서 이 문제를 해결할 방법을 찾지 못하고 있습니다. 혹시나 아시는 분은 꼭 가르쳐주시기를 바랍니다. |
다음은 제가 오라클 기술지원 센터에서 받은 답변의 일부입니다.
선생님께 발생하신 문제는 특정 코드 range의 data를 8i thin driver가 핸들링하지 못할때 발생하는 문제로 보여집니다. 특정 코드값의 data를 fetch하는 과정에서 null data packet이 발생하는데, 그런 경우 protocol violation error가 발생합니다. |
보통은 Oracle JDBC Driver의 버젼이 원인인 경우가 많은데 Database를 오래전부터 써왔고 파워빌더, CGI 등 여러 C/S 어플리케이션이 접속을 하는 환경이라면 위와 같은 해결방법을 찾으셔야 합니다.
첫번째의 경우는 지금 쓰고 있는 JDBC Driver의 버젼을 알아내고 최신의 JDBC Driver를 설치해주시면 됩니다.
Test2.java (파일 첨부)
Class.forName ("oracle.jdbc.driver.OracleDriver"); DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); Connectioncon = DriverManager.getConnection(""); Statement stmt = null; DatabaseMetaData dbm= con.getMetaData(); System.out.println("Product Name :"+dbm.getDatabaseProductName()); System.out.println("Product Version :"+dbm.getDatabaseProductVersion()); System.out.println("Driver Major Version :"+dbm.getDriverMajorVersion()); System.out.println("Driver Minor Version :"+dbm.getDriverMinorVersion()); System.out.println("Driver Name :"+dbm.getDriverName()); System.out.println("Driver Version :"+dbm.getDriverVersion()); |
현재 오라클 JDBC Thin Driver의 버젼은
8.1.6.x.
8.1.7.0
8.1.7,1 ß--- Recommended
9.0.1.0
이렇게 4개의 버젼이 오라클 홈페이지에 올라와 있습니다. 되도록이면 DBMS가 8 버젼이라면 8.1.7.1을 쓰실 것을 권장합니다. 그리고 Oracle DBMS의 Thin-Driver와 버젼을 맞춰줘야 한다는 얘기도 있지만 특별한 Operation이 아니면 서버의 JDBC Driver는 타지 않는다는 오라클 엔지니어의 답변이 있었습니다. 그냥 기존의 classes12.zip을 교체만 해주면 됩니다.
두번째 경우는 LONG 또는 에러가 나는 String 타입의 컬럼을 가져올때 getString 말고 아래와 같이 써주면 됩니다. 이 부분은 otn.oracle.co.kr에 많은 질문과 답변이 있습니다.
StringBuffer sb = new StringBuffer(); char[] buffer = new char[1024]; int bytesRead; try { Reader Rd = rs.getCharacterStream("TITLE"); while ((bytesRead = Rd.read(buffer, 0, 1024)) != -1) { sb.append(buffer, 0, bytesRead); } Rd.close(); } catch (IOException e) { System.out.println(e.getMessage()); } title = sb.toString(); |
세번째 경우, 자바 서비스넷(javaservice.net)에 올라오는 질문의 대부분이 이 문제인거 같습니다. 저도 SI 나간 곳에서 문제를 접하게 되었고 오라클 기술 지원에 문의해서 해결 했습니다. 이 경우 해결책은 두가지 입니다.
1. JDBC 연결 방식을 OCI로 변경한다.
2. 오라클 DBMS를 9i로 업그레이드 한다.
OCI 변경은 JDBC 접속을 하는 Node에 오라클 클라이언트를 설치 해주면 됩니다. Net8 접속환경을 만들어 주기 위해선데 DBMS의 버젼보다 높은 걸 써도 아무 문제가 없습니다.
(간단히 말하자면 sql_plus가 접속할 수 있는 환경을 만들어 주는 것입니다.)
대신 OCI와 Thin을 공존해서 쓸 경우가 많으므로 (성능 차이는 거의 나지 않다는 Perfomance 보고서가 있지만 문제가 없는 부분에 까지 OCI 연결 방식을 쓸 필요는 없는 것 같습니다.
Classes12.zip에는 오라클 Thin JDBC 클래스와 OCI JDBC 클래스가 함께 들어 있으므로 가장 최신인 8.1.7.1을 쓰기 위해선 오라클 클라이언트도 8.1.7.1을 쓰길 권장합니다.
8.1.7.1이 따로 있는지는 잘 모르겠지만 OCI 연결 방식은 오라클 클라이언트 버젼과 Oracle JDBC 클래스 버젼과 같아야만 동작합니다. (저의 경우는 그래서 눈물을 머금고 8.1.7.0을 쓰고 있습니다.)
주의> 오라클 클라이언트 8.1.7.0 ß-à 오라클 JDBC Classes12.zip 8.1.7.0
버젼이 안맞으면 나중에 연결 시 Unsatisfied Link Error 가 납니다.
오라클 클라이언트 설치 및 OCI 접속 환경 셋팅은 오라클 관련 문서를 찾아보시거나 해당 엔지니어에게 문의 해주세요.
접속은 tnsnames.ora 파일에 Alias를 추가해 주면 됩니다.
TOM = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = www.xxxx.net)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = ORCL) ) ) |
이런식으로 모든 환경 Setting 이 완료된 후
(자세한 내용은 http://www.oracle.com/kr/support/web_supports/bulletins/ 에서 검색해 보시면 됩니다. 죄송 get 방식의 url이 없는 지라…-.-)/ )
url만 바꿔 주시고 연결을 확인하시면 됩니다.
private final static String url = "jdbc:oracle:oci8:@tom"; |
마무리
저의 개발 환경은 솔라리스 + 오라클 8.1.6 DBMS 였고
현재 8.1.7.0 오라클 classes12.zip으로 Thin 연결과 OCI 연결을 혼용해서 쓰고 있습니다.
둘다 ConnectionPool을 적용해 문제가 되는 데이터열이 많은 테이블에만 OCI 접근방식을 이용하고 있습니다.
음..일단 웬만한 질문에 대한 답변은 자바서비스넷의 고수님들의 글을 활용하시면 되겠습니다. 그리고 후에 제가 쓰고 있는 ConnectionPool에 대해 문서를 올리도록 하겠습니다.
(웹에서 구한 여러 ConnectionPool이 있지만 가장 신뢰성있는 ConnectionPool입니다. 전에는 맨날 오라클 커넥션 Process가 남아 톰캣 내렸다 올렸다 해야 했는데 요즘은 전혀 문제 없습니다.)
레퍼런스
자바 서비스넷 게시물 1개
SCJP
안기현