포토로그



iBatis, DBCP 그리고 MySQL JDBC Driver

iBatis로 쿼리를 실행하면 쿼리를 직접 실행할 때보다 4배나 느렸다. 출시가 며칠 안 남았는데... 프로파일링을 해보니 의도한 쿼리를 실행하는 것보다 커넥션 풀에서 커넥션을 꺼내거나 트랜잭션을 시작하고 종료할 때 setAutoCommit이 여러 번 실행되고 여기서 시간을 많이 쓰고 있었다.

하루 종일 설정을 이리 저리 바꾸며 삽질하다 iBatis, DBCP, MySQL JDBC 드라이버의 소스를 뒤져서 원인을 알아냈다. 각각이 요구하는 autoCommit 설정과 기본 설정이 다르기 때문이었다. iBatis JDBC TransactionManager는 autoCommit=false이어야 한다. 커넥션 풀에서 꺼낸 커넥션이 autoCommit=false가 아니면 setAutoCommit(false)를 실행해서 autoCommit을 끈다. setAutoCommit(false)이 실행되지 않도록 DBCP의 defaultAutoCommit을 false로 설정하면 JDBC TransactionManager는 setAutoCommit을 더 이상 실행하지 않는다.

여기서 끝이었으면 좋겠지만... DBCP defaultAutoCommit을 false로 설정해도 setAutoCommit은 계속 실행된다. 이유는 DBCP가 setAutoCommit(false)를 실행하기 때문이다. DBCP도 JDBC TransactionManager와 마찬가지로 생성한 커넥션이 defaultAutoCommit으로 설정한 값과 다르면 setAutoCommit을 실행한다. MySQL JDBC Driver는 autoCommit=false가 기본 값이다. 그러므로 DBCP의 defaultAutoCommit을 false로 설정하면 DBCP가 setAutoCommit을 실행한다.

DBCP의 defaultAutoCommit을 true로 두면 iBatis가 setAutoCommit을 실행하고, false로 설정하면 DBCP가 setAutoCommit을 실행한다. 그럼 어떻게 하나? JDBC Driver에서 기본 autoCommit 값을 바꿀 수 있다면 문제가 없지만 MySQL JDBC Driver는 기본 autoCommit 값을 설정할 수 없는 것 같다. 그럼 어쩌나? iBatis에서 JDBC 대신 EXTERNAL TransactionManager를 쓰고 DefaultAutoCommit 프로퍼티를 true로 설정하고 DBCP의 defaultAutoCommit도 true로 설정하면 된다. EXTERNAL TransactionManager를 쓰면 iBatis가 트랜잭션을 관리하지 않는다. 즉 commit, rollback을 실행하지 않는다. commit이 실행되지 않으면 쿼리의 효과가 없기 때문에 DefaultAutoCommit을 true로 지정하여 commit이 실행되지 않아도 쿼리가 효과를 낼 수 있도록 한다.

결론은 iBatis TransactionManager, DBCP, JDBC Driver의 autoCommit 설정이 다르면 setAutoCommit이 많이 실행되니까 맞춰야 한다.


덧글

  • benelog 2010/07/09 21:31 # 삭제 답글

    프로파일링할 때는 주로 어떤 거 쓰세요?
  • 이피 2010/07/09 23:43 # 답글

    전 YourKit이나 JProfiler 써요. JProbe는 쓰기가 어렵더군요.
댓글 입력 영역