Whiteship's Note


스프링에서 하이버네이트와 JDBC 같이 사용할 때 트랜잭션 처리는?

Hibernate/etc : 2008.10.08 16:23


별로 할 일이 없습니다.

PlatformManager는 하이버네이트가 사용하는
org.springframework.orm.hibernate3.HibernateTransactionManager

이걸 그대로 사용하면 되고, JDBC 코딩을 할 때는 그냥 JdbcTemplate을 사용하면 알아서 트랜잭션이 적용됩니다.

그런데 만약에 JdbcTemplate을 사용하지 못하고, DataSource를 직접 사용해야 할 경우에는 다음과 같이 TransactionAwareDataSourceProxy를 사용하면 된다고 합니다.

<bean id="rawDataSource" class="whatover youuse"/>

<bean id="dataSource" class="TransactionAwareDataSourceProxy">
  <constructor-arg ref="rawDataSource" />
</bean>

DataSource를 직접 사용하는 코드가 엄청나게 많아서 손을 못댈 경우에는 저렇게 dataSource를 스프링이 관리하는 트랜잭션을 알고 있는 데이터소스로 바꾸면 된다고 하는데, 해보진 않았습니다. 제가 해보고 싶었던 건 하이버네이트가 flush()를 하지 않은 데이터에 대한 JDBC쿼리로 인한 예외 상황인데...

테스트를 잘못 짠건지.. 잘 안 되더군요.

@Repository
public class MemberDao {

    @Autowired
    SessionFactory sessionFactory;
   
    SimpleJdbcTemplate jdbcTemplate;
   
    @Autowired
    public MemberDao(DataSource dataSource) {
        jdbcTemplate = new SimpleJdbcTemplate(dataSource);
    }
   
    public void add(Member member){
        sessionFactory.getCurrentSession().save(member);
    }
   
    public int update(Member member){
        return jdbcTemplate.update(
                "UPDATE Member SET age = ? WHERE name = ?", member.getAge(), member.getName());
    }

}

이런 DAO를 만들었습니다. add()는 하이버네이트로하고 update()는 JdbcTemplate으로 했습니다.

@Service
@Transactional
public class MemberService {

    @Autowired
    MemberDao memberDao;
   
    public void foo(){
        Member member = new Member();
        member.setName("keesun");
        memberDao.add(member);
       
        member.setAge(20);
        memberDao.update(member);
    }
   
}


그리고 서비스 코드는 저렇게 트랜잭션 처리를 하고, keesun이라는 객체를 하나 만들어서 저장하고, 나이를 추가한다음에 JDBC로 update문을 날립니다.

제가 원했던 결과는..

에러가 나는 겁니다.

그러나..

Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into Member (age, name, id) values (?, ?, ?)
Hibernate: update Member set age=?, name=? where id=?

에러가 나질 않고, 너무도 자연스럽게 동작해버려서 당황했습니다. 특히 마지막 줄의 쿼리는 제가 JdbcTemplate으로 날린 쿼리랑은 완전 다른 하이버네이트가 만든 쿼리가 날아갔습니다. 이게 대체;;; 무슨 일인지..  흠..

결과적으로는 아~무 걱정없이 하이버네이트랑 JdbcTemplate을 같이 사용할 수 있다는 것이지만, 제가 원했던 상황이 발생하지 않아서 좀 우울합니다.
top


AbstractTransactionalDataSourceSpringContextTests



아 굉장히 기다란 클래스 이름입니다. 한글로는 "추상 트랜잭셔널 데이타소스 스프링 컨텍스트 테스츠" 클래스. 일종의 농담입니다. -_-;;

AbstractTransactionalDataSourceSpringContextTests 클래스 API를 보았습니다.
분홍색 윗 부분은 JUnit 프레임웍입니다. 이 클래스는 기본적으로 JUnit 프레임웍 기반으로 만들어졌슴을 알 수 있습니다. 그러므로 assertEquals(int a, int b) 와 같은 test에 유용한 JUnit의 메소드들을 사용할 수 있었던 것입니다.

JdbcTemplate 클래스 살펴 보기
그리고 가지고 있는 member 변수로는 jdbcTemplate이 있으며 API를 인용하면 다음과 같습니다.
This is the central class in the JDBC core package. It simplifies the use of JDBC and helps to avoid common errors. It executes core JDBC workflow, leaving application code to provide SQL and extract results. This class executes SQL queries or updates, initiating iteration over ResultSets and catching JDBC exceptions and translating them to the generic, more informative exception hierarchy defined in the  org.springframework.dao.pachage.JDBC 사용을 간편하게 해주는 객체 인듯 합니다.
AbstractTransactionalSpringContextTests 클래스 살펴 보기

멤버와 상속구조를 살펴 봐서는 대체 어떤 녀석인지 아직도 감이 잡히지 않습니다. 이 클래스의 API를 보면  "AbstractTransactionalSpringContextTests를 상속받은 클래스로 몇가지 편리한 기능을 추가를 했다. Expects a DataSource to be defined in the Spring application context.(?) 이 클래스는 JdbcTemplate을 가지고 있으며 트랜잭션을 DB에서 지우는 편리한 방법을 제공한다." 라고 나와있습니다.(가운데 문장은 해석이잘 안됨.ㅠ.ㅠ)

그래서 상위 클래스인 AbstractTransactionalSpringContextTests API를 살펴보았습니다.

트랙잭션이 발생 시키는 테스트를 할 때 유용한 슈퍼 클래스지만 기본적으로 트랜잭션을 각각의 테스트 메소드가 끝날 때 마다 롤백 시킨다.

다음과 같은 상황일 때 유용하다.
  • 다른 test에 영향을 주지않고 DB에 data을 넣거나 삭제 할 때.
  • 트랜잭션이 필요한 코드를 위해 transactional context를 제공
  • 굳이 청소할 필요없이 DB에 아무거나 집어 넣어 볼때.
다음과 같은 유용한 메소드도 제공합니다.
  • setComplete() - 트랜잭션을 롤백 시키고 싶지 않을 때(DB에 추가, 삭제한 결과를 남기고 싶을때 사용)
  • endTransaction() - 트랜잭션을 좀더 빨리 끝내고 싶을 때(잘 모르겠네요. O/R mapping의 초기화 지연 기법을 검증할 때 사용할 수 있다는데 O/R mapping이 뭔지 모르겠네요.)
  • startNewTransaction() - endTransaction() 호출 뒤에 이전 트랜잭션에 독립적인 새로운 트랜잭션을 시작할때 사용(역시.. endTransaction() 커플로 어떻게 언제 쓰는건지 모르겠습니다.)

아직은 뭔가 알아내야 할 것이 많군요. OTL 갈길이 너무 멀다. 멀다 한들 멈추리오..

'Spring > 주소록 만들기' 카테고리의 다른 글

수정해야 할 것들  (2) 2006.11.28
iBATIS에서 selectKey 사용하기  (2) 2006.11.23
MySQL 설치 시 주의 할 점  (6) 2006.11.23
DB 인코딩 문제  (0) 2006.11.20
SqlMapClientDaoSupport  (0) 2006.11.18
AbstractTransactionalDataSourceSpringContextTests  (4) 2006.11.13
회원 목록 추가  (0) 2006.11.13
XML configuration  (0) 2006.11.10
MySQL Connector Down + testAdd()  (0) 2006.11.10
MySQL 설치 + 사용  (1) 2006.11.09
프로젝트 생성 + jar 파일 추가  (0) 2006.11.09
top