QueryService에서 CallableStatement 사용은 어떻게 해야 하나요?
환경이 Oracle => Tibero로 바뀌면서 발생한 문제 입니다.
프로시져가 리턴 변수를 사용해서 프로시져의 성공 실행 여부를 가져오는 프로시져입니다.
호출하는 jdbc test 코드는 다음과 같습니다.
.......
Connection subConn = null;
subConn = DriverManager.getConnection(tibero_url, tibero_id, tibero_pwd);
CallableStatement cstmt = null;
cstmt = subConn.prepareCall("CALL syncSvcCiTrAndMbSvcTr(?)");
cstmt.registerOutParameter("o_result", java.sql.Types.VARCHAR);
cstmt.execute();
System.out.println("test result: " + cstmt.getString("o_result"));
.....
jdbc코딩에서는 다음과 같이 호출하여서 사용하는데
Anyframe의 QueryService에서는 ibatis와 함께 어떻게 호출해야 하나요?
참고로 DB가 Oracle일때는
xxxxImpl.java
......
HashMap hmOut = new HashMap();
hmOut.put("o_result", "");
Map hmResult = queryService.execute("call_syncSvcCiTrAndMbSvcTr", hmOut);
if ( hmResult != null ) {
String sResult = StringUtils.toString(hmResult.get("o_result"));
if ( sResult.equals("SUCCESS"))
bResult = true;
.......
mapping-xxxxx.xml
< query id="call_syncSvcCiTrAndMbSvcTr" isDynamic="true" mappingStyle="lower">
< statement>
CALL syncSvcCiTrAndMbSvcTr(?)
<끝 statement >
< param type="VARCHAR2" binding="OUT" name="o_result" />
<끝 query >
* 슬레쉬하면 글자가 나오지 않아 / => 끝
와 같이 프로시져에 호출변수를 선언해 주는것이 아닌 입력번수로만 입력해도 동작이 됐었습니다.


Re] QueryService에서 CallableStatement 사용은 어떻게 해야 하나요?
문의하신 내용이 다음과 같았는데 정확히 원하시는 것이 무엇인지요? QueryService와 iBatis를 연동하여 사용하고자 하신 것인지요? Anyframe에서는 iBatis에 대한 지원은 하고 있지 않아서 답변을 드리기 어려울 것 같습니다.
또한 DBMS를 Oracle을 사용하든 Tibero를 사용하든 QueryService를 사용하는 코드는 변경되지 않습니다.
문의 사항중에 언급하신 JDBC 코드에서와 마찬가지로 QueryService에서도 이러한 JDBC 사용 로직을 그대로 사용하고 있습니다. 따라서 DBMS에 특화된 로직을 수행하고 있지 않습니다.
결국 하고자 하는것은 Anyframe에서 결과 값을
결국 하고자 하는것은 Anyframe에서 DB에 있는 결과 값을 넘겨주는 프로시져를 콜하는 방법이 무엇인지 알고 싶습니다.
Re] 결국 하고자 하는것은 Anyframe에서 결과 값을 ....
프로시저가 다음과 같이 정의되어 있다라고 가정해 보겠습니다. 다음 프로시저는 DATE 타입의 입력값을 기준으로 VARCHAR2 타입의 출력값을 던져주게 됩니다.
이 프로시져를 실행시키기 위해서 매핑 XML 파일은 다음과 같이 정의하게 됩니다.
<query id="callProcedure" isDynamic="false"> <statement>{call PROC_TOCHAR_SYSDATE (?,?)}</statement> <param type="VARCHAR" binding="OUT" name="outVal" /> <param type="DATE" binding="IN" name="inVal" /> </query>끝으로 QueryService 활용 로직은 다음과 같습니다.
public void testProcedure() throws Exception { // 1. set data for test HashMap inVal = new HashMap(); inVal.put("inVal", new Timestamp(DateUtil.string2Date("20081111", "yyyyMMdd").getTime())); // 2. execute query Map results = queryService.execute("callProcedure", inVal); // 3. assert assertTrue("Fail to execute function.", results.size() == 1); assertEquals("Fail to compare class type of outVal.", String.class, results.get("outVal").getClass()); assertEquals("20081111", results.get("outVal")); }보다 자세한 내용은 Anyframe Subversion에 있는 anyframe.query 프로젝트의 테스트코드 QueryServiceCallableStatementTest.java와 testcase-queries-procedure.xml 파일을 참조하시기 바랍니다.
Tibero DB4 에서 테스트 부탁 드립니다.
안내 해주신대로 QueryServiceCallableStatementTest.java와 testcase-queries-procedure.xml 파일을
참조해서 테스트를 진행했습니다.
Oracle에서는 해당 테스트 케이스가 정상 수행 하였습니다.
Tibero DB에서는 다음과 같은 메세지를 발생 시키면서 테스트 케이스가 정상 수행되지 않았습니다.
-- Error Code --
010-08-13 14:24:23,281 ERROR [anyframe.core.query.IQueryService] Query Service : Fail to execute statement [query id = 'callProcedure'].
Query = [{call PROC_TOCHAR_SYSDATE (?,?)}]
Reason = [sql; nested exception is com.tmax.tibero.jdbc.TbSQLException: TJDBC-90201:Unsupported operation.].
anyframe.core.query.impl.util.InternalDataAccessException: sql; nested exception is
com.tmax.tibero.jdbc.TbSQLException: TJDBC-90201:Unsupported operation.
at anyframe.core.query.impl.util.RawSQLExceptionTranslator.translate(RawSQLExceptionTranslator.java:31)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:952)
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:985)
at anyframe.core.query.impl.QueryServiceImpl.execute(QueryServiceImpl.java:324)
at anyframe.core.query.impl.QueryServiceImpl.execute(QueryServiceImpl.java:291)
at anyframe.core.query.impl.QueryServiceImpl.execute(QueryServiceImpl.java:286)
at anyframe.core.query.impl.QueryServiceCallableStatementTest.testProcedure(QueryServiceCallableStatementTest.java:220)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: com.tmax.tibero.jdbc.TbSQLException: TJDBC-90201:Unsupported operation.
at com.tmax.tibero.jdbc.TbCallableStatement.registerOutParameter(TbCallableStatement.java:877)
at org.apache.commons.dbcp.DelegatingCallableStatement.registerOutParameter(DelegatingCallableStatement.java:171)
at org.springframework.jdbc.core.CallableStatementCreatorFactory$CallableStatementCreatorImpl.createCallableStatement(CallableStatementCreatorFactory.java:192)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:930)
... 25 more
Root cause follows.
com.tmax.tibero.jdbc.TbSQLException: TJDBC-90201:Unsupported operation.
at com.tmax.tibero.jdbc.TbCallableStatement.registerOutParameter(TbCallableStatement.java:877)
at org.apache.commons.dbcp.DelegatingCallableStatement.registerOutParameter(DelegatingCallableStatement.java:171)
at org.springframework.jdbc.core.CallableStatementCreatorFactory$CallableStatementCreatorImpl.createCallableStatement(CallableStatementCreatorFactory.java:192)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:930)
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:985)
at anyframe.core.query.impl.QueryServiceImpl.execute(QueryServiceImpl.java:324)
at anyframe.core.query.impl.QueryServiceImpl.execute(QueryServiceImpl.java:291)
at anyframe.core.query.impl.QueryServiceImpl.execute(QueryServiceImpl.java:286)
at anyframe.core.query.impl.QueryServiceCallableStatementTest.testProcedure(QueryServiceCallableStatementTest.java:220)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Re] Tibero DB4 에서 테스트 부탁 드립니다.
현재 저희가 Tibero DB를 보유하고 있지 않아 테스트가 어려울 것 같습니다. 단, 보여주신 에러 로그로 보았을 때 일반적으로 JDBC 기반에서 프로시져 실행시 OUT에 해당하는 Parameter를 셋팅해주어야 하는데 이 부분에서 Tibero에서 제공하는 'TbCallableStatement' 클래스가 registerOutParameter()라는 오퍼레이션 실행시 "Unsupported operation" 라는 메시지를 전달하고 있는 것으로 생각됩니다.
다음은 위에서 보여주신 에러 로그의 일부로 현재 발생하는 에러의 원인을 보여주는 부분입니다.
위 메소드는 QueryService가 아닌 일반 JDBC 기반 프로그래밍 수행시에도 호출하는 로직이므로 JDBC 기반으로 CallableStatement를 실행해 보시기를 권장합니다.
만약 이 경우에도 동일한 에러가 발생한다면 Tibero 엔지니어에게 문의해 보시는 것이 좋을 것 같습니다.
JDBC 기반에서 CallableStatement를 실행하기 위해서는 다음과 같은 형태로 구현하실 수 있습니다.
public void testProcedureByJdbc() throws Exception { Connection conn = null; String rs = null; CallableStatement statement = null; try { // 1. get connection conn = this.dataSource.getConnection(); // 2. execute CallableStatement statement = conn.prepareCall("{call PROC_TOCHAR_SYSDATE (?,?)}"); statement.setDate(1, new Timestamp(DateUtil.string2Date("20081111", "yyyyMMdd").getTime())); statement.registerOutParameter(2, java.sql.Types.VARCHAR); statement.execute(); // 3. get result rs = (String) statement.getObject(2); System.out.println(rs); } catch (Exception e) { fail("Fail to execute Oracle package. Reason : " + e.getMessage()); } finally { statement.close(); conn.close(); } }