트랜잭션 기초

  • Atomic: 원자성
  • Consistency: 비지니스 룰을 깨트리면 안 된다.
  • Isolation: 동시에 같은 데이터에 대한 여러 작업이 독립적으로 수행되어야 한다.
  • Durability: 트랜잭션의 결과는 영속적으로 유지되어야 한다.

Chapter 10: Transactions

참조 : The Programmer’s Guide to SQL

트랜잭션의 특징 ACID
    – Atomic
    – Consistency
    – Isolation
    – Durable

오라클은 기본으로 Auto Transaction 상태.
    – 첫 번째 SQL문을 실행할 때, 트랜잭션이 자동으로 시작 됨.
    – 따라서 START TRANSACTION(SQL-99 표준) 을 사용하지 않아도 됨.
    – 그러나 10g에서는 기본으로 오토커밋 상태임.

사용자 삽입 이미지
오토커밋
    – 이 상태에서는 모든 SQL문을 개별 트랜잭션으로 처리함.
    – SET AUTOCOMMIT ON/OFF 오라클에서 오토커밋 상태로 전환 하는 방법.

롤백하기
    – ROLLBACK [세이브포인트 이름]
    – SAVEPOINT 이름 생략하면, 트랜잭션 시작 이전 상태로 돌아감.

세이브포인트 만들기
    – SAVEPOINT [이름];

커밋하기
    – COMMIT

트랜잭션 예제

BEGIN

   INSERT INTO Student (StudentID, Name) VALUES (101, ‘Dave’);
   INSERT INTO Student (StudentID, Name) VALUES (102, ‘Claire’);

   SAVEPOINT BeforeAddingAnne;
   INSERT INTO Student (StudentID, Name) VALUES (103, ‘Anne’);
   ROLLBACK TO BeforeAddingAnne;

   COMMIT;

EXCEPTION
   WHEN OTHERS
      THEN ROLLBACK;
END;
/

오라클의 Isolation level
    – 기본은 Read Commited
    – Read Uncommited와 Repeatable Read는 지원하지 않음.
    – Isolaction Level 변경하는 방법
    SET TRANSACTION
    { { READ ONLY | READ WRITE }
      | ISOLATION LEVEL
        { READ COMMITTED
        | SERIALIZABLE } };

동기화 테스트 하려면, 오토커밋 상태가 아닌 상태에서 두 개의 창을 띄워 놓고 하면 됨.(READ COMMITED 상태)
    – 한 쪽 창에서 한 개의 레코드를 추가한다.
    – 추가 됐는지 SELECT 문으로 확인한다.
    – 다른 쪽 창에서 SELECT 해본다.
    – 다른 쪽 창에는 첫 번째 창에서 추가한 레코드가 보이지 않는다.
    – 첫 번째 창의 SQL이 아직 커밋되지 않았기 때문이다.
    – 첫 번째 창에서 COMMIT 을 실행한다.
    – 두 번째 창에서 SELECT로 확인한다. 이번에는 보인다.

Transaction 관련 API

J2EE without EJB p242 의 그림입니다.
사용자 삽입 이미지
TransactionDefinition, TransactionStatus, PlatformTransactionManager
사용자 삽입 이미지
PlatformTransactionManager 인터페이스를 구현한 클래스들

AbstractPlatformTransactionManager, CciLocalTransactionManager, DataSourceTransactionManager, HibernateTransactionManager, HibernateTransactionManager, JdoTransactionManager, JmsTransactionManager, JmsTransactionManager102, JpaTransactionManager, JtaTransactionManager, OC4JJtaTransactionManager, TopLinkTransactionManager, WebLogicJtaTransactionManager

TransactionDefinition 인터페이스르 구현한 클래스들

DefaultTransactionAttribute, DefaultTransactionDefinition, DelegatingTransactionAttribute, RuleBasedTransactionAttribute, TransactionTemplate

TransactionException 은 모두 RuntimeException으로 un-checked Exception입니다.
사용자 삽입 이미지

9.7. Choosing between programmatic and declarative transaction management

programmatic transaction management

트랜잭션 처리를 할 부분이 매우 일부라면 트랜잭션 프록시 같은 것을 사용하지 않고 그냥 TransactionTemplate 을 사용하여 처리하는 것을 권장합니다.

트랜잭션 이름을 명시적으로 사용할 수 있다는 것도 이런 방법의 장점 중 하나입니다.[footnote]선언적인 방법에서는 트랜잭션 이름을 (아직까진) 명시적으로 줄 수 없었습니다.[/footnote]

declarative transaction management

트랜잭션 처리 할 부분이 많다면 비즈니스 로직에서 분리 해내고 쉽게 설정할 수 있는 요 방법을 사용하는 것이 좋습니다.

9.6. Programmatic transaction management

선언적인 방법이 아니고 프로그래밍을 통해 트랜잭션 관리를 할 때 두 가지 경우가 있습니다.
1. TransactionTemplate 사용 할 경우
2. PlatformTransactionManager 를 구현한 클래스를 직접 사용 할 경우

9.6.1. Using the TransactionTemplate

private final TransactionTemplate transactionTemplate;

이렇게 멤버로 지정해 놓고 사용하면 됩니다. 먼저 트랜잭션의 속성을 설정하는 방법은 다음과 같습니다.

    public SimpleService(PlatformTransactionManager transactionManager) {
        Assert.notNull(transactionManager, “The ‘transactionManager’ argument must not be null.”);
        this.transactionTemplate = new TransactionTemplate(transactionManager);

        // the transaction settings can be set here explicitly if so desired         this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
        this.transactionTemplate.setTimeout(30); // 30 seconds
        // and so forth…
    }

아니면 XML에서 설정하고 세터나 생성자 인젝션을 사용하면 되겠습니다.

<bean id=”sharedTransactionTemplate”
      class=”org.springframework.transaction.support.TransactionTemplate>
    <property name=”isolationLevelName” value=”ISOLATION_READ_UNCOMMITTED”/>
    <property name=”timeout” value=”30″/>
</bean>

트랜잭션 탬플릿을 사용해서 어떤 작업을 할 때는 다음과 같이 TransactionCallback 을 사용합니다. 탬플릿과 콜백에 대한 이해는 이 글을 참조하시길 초 강추 합니다.

1. 리턴 값이 있는 경우

public Object someServiceMethod() {
        return transactionTemplate.execute(new TransactionCallback() {

            // the code in this method executes in a transactional context
            public Object doInTransaction(TransactionStatus status) {
                updateOperation1();
                return resultOfUpdateOperation2();
            }
        });
    }

2. 리턴 값이 없는 경우

public void someServiceMethod2() {
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
   
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            updateOperation1();
            updateOperation2();
        }
    });
}


9.6.2. Using the PlatformTransactionManager

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setTransactionName(“SomeTxName”);
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);
try {
    // execute your business logic here
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);

TransactionDefinition, TransacionStatus, TransactionManager 객체를 직접 사용하여 트랜잭션 속성을 설정하고 롤백 또는 커밋을 하는 코드를 직접 작성하는 방법입니다. 이 세개의 객체들에 대한 관계는 without EJB의 트랜잭션 부분 242페이지에 잘 나와있습니다.