Framework/iBatis2008. 3. 10. 16:35
얼마전 프로젝트를 진행 중 iBatis에서 Procedure를 사용하고 Transaction을 Commit을 했으나, Commit이 되지 않고 모두 Rollback이 되는 현상이 발생을 했다.
아직 이 문제가 발생하는 근본 원인은 파악을 하지 못했고, 해결 방안만 찾아 사용했다. 해결 방안을 간단하게 정리한다. 소개는 실제 사용한 소스가 아니니 참고하세요.

-- 환경 설정
iBatis : iBatis 2.3.0
DB : Oracle 10g
Framework : Webwork 2.2.6, Spring 2.0.7

-- Commit 되지 않는 문제 발생
iBatis를 통해 실행 할 Procedure는 아래와 같이 TB_EMP 테이블에 NO와 NAME을 받아서 INSERT하는 Procedure이다. 그리고, Procedure 내에서 Transaction을 관리하지 않고, iBatis에서 Transaction을 관리하게 구성되어 있다.

Oracle Procedure :
   CREATE OR REPLACE PROCEDURE SP_TEST
      (p_no IN TB_EMP.NO%TYPE, p_name IN TB_EMP.NAME%TYPE)
   IS
   BEGIN
      INSERT INTO TB_EMP (NO, NAME) VALUES (p_no, p_name);
   END;

iBatis SqlMap :
   <parameterMap id="empMap" parameterClass="java.util.Map">
      <parameter property="no" mode="IN" jdbcType="DECIMAL" javaType="int" />
      <parameter property="name" mode="IN" jdbcType="VARCHAR" javaType="java.lang.String" />
   </parameterMap>
   <procedure id="insertEmpInfo" parameterMap="empMap" >
      { CALL SP_TEST(?, ?) }
   </procedure>

Execute Java Source :
   private SqlMapClient sqlMapClient = null;

   public void insertEmpInfo(int no, String name) throws SQLException {
      java.util.Map<String, Object> conditionMap = new java.util.HashMap<String, Object>();
      conditionMap.put("no", no);
      conditionMap.put("name", name);

      try {
         // start transaction
         sqlMapClient .startTransaction();
         
         sqlMapClient.queryForObject("insertEmpInfo", conditionMap);

         // commit transaction
         sqlMapClient.commitTransaction();
      } finally {
         // rollback and end transaction
         sqlMapClient.endTransaction();
      }
   }

위와 같은 코드에서는 Exception이 발생하지 않고 commitTransaction()이 실행 되었음에도 실제 DataBase에는 commit이 되어 있지 않고 rollback이 되어 있다.
그러나 같은 Transaction에서 Procedure와 함께 INSERT, UPDATE, DELETE Query가 실행이 되면 commit은 정상적으로 된다. 함께 실행되는 Query가 Procedure 전, 후 어디에서 실행이 되어도 상관은 없다. 왜 commit 되지 않는 것인가 원인은 아직 찾지를 못했고, 해결 방안만을 찾았다.

-- 해결 방안
   public void insertEmpInfo(int no, String name) throws SQLException {
      java.util.Map<String, Object> conditionMap = new java.util.HashMap<String, Object>();
      conditionMap.put("no", no);
      conditionMap.put("name", name);

      try {
         // start transaction
         sqlMapClient .startTransaction();
         
         sqlMapClient.queryForObject("insertEmpInfo", conditionMap);

         // commit transaction
         sqlMapClient.commitTransaction(); è sqlMapClient.getCurrentConnection().commit();
      } finally {
         // rollback and end transaction
         sqlMapClient.endTransaction();
      }
   }

위와 같이 sqlMapClient의 Session에 저장 된 Connection을 commit() 하는 것이 아니라 sqlMapClient의 현재 User Connection을 가져와 강제로 commit()을 해주면 INSERT, UPDATE, DELETE Query를 같이 사용하지 않는 경우에도 commit이 정상 처리 된다.

이 문제는 일부 JDBC Driver에서만 발생하는 문제인지, iBatis의 문제인지는 아직 확인을 하지 못 했다.
Posted by as.wind.914