날아라쩡글이의 블로그입니다.

트랜잭션 @transactional 본문

중앙 HTA (2106기) story/spring java framwork story

트랜잭션 @transactional

날아라쩡글이 2022. 1. 11. 13:25
반응형

트랜잭션이란 은행업무를 볼때 계좌이체를 진행하면 상대방계좌 증액, 내 계좌 감액이 이뤄지는데, 중간에 에러가 났을 때 이 두가지의 업무 진행이 한꺼면에 All or Not으로 진행이 되거나 취소가 되는 것을 의미한다.

Service에서 엄청난 여러 작업들이 존재하며 DB Access가 이뤄진다. inser, update, delete의 작업이 이뤄지고, 업무로직 처리하거나 클라이언트의 요청을 처리할 때 All or Nothing 경우 외에는 없어야한다는 원칙이다. 

  • 전부 완벽하게 저장하거나 하나도 적용되지 않는것이다. 
  • DB Access의 작업이 바로 반영되지 않고, 작업이 완료되어야 commit이 이뤄지고 중간에 error가 발생하게 되면 rollback이 이뤄지는것이다. 
  • spring에서는 선언적 트랜잭션의 처리를 지원한다. 
    • 트랜젝션의 코드를 작성하는 것이아니라 필요한 곳이 어디인지 어노테이션으로 선언하면 해당 메소드 실행시 서비스를 실행할 수 있다. 
  • 그것이 트랜잭션 매니저이다. 
    • 항상 대상은 서비스이다. 서비스 메소드시 트랜잭션의 처리가 지원되어야한다. 
    • 선언적 트랜잭션 처리를 지원하는 transactionManager의 객체를 제공한다. 
  • 선언적 트랜잭션처리가 적용되는 곳은 서비스 객체의 업무로직 메소드다. 
    • 여러번의 DB Access를 한다. 
    • select은 조회이기 때문에 하지 않고, update, insert, delete처럼 2번이상의 호출시 필수적으로 사용한다. 
  • 선언적 트랜잭션 처리를 지원받기 위해서는 @Transactional를 인터페이스, 클래스 혹은 메소드에 부착하면 된다. 

2가지 방식

  • 선언적 방식은 2가지가 있다
  • 첫번째 방식은 어노테이션을 사용하는 방식
  • 두번째 방식은 AOP방식이 존재한다. 

어노테이션 방식

  • context-root에 dataSource에 의존하는 TxManager를 설정한다. 
    • <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
       </bean>
    • 선언적 트랜잭션 처리를 지원하는 트랜잭션 매니저 객체를 스프링 컨테이너에 등록시키기 
      • spring-jdbc, ibatis, mybatis를 사용해서 데이터베이스 엑세스를 구현한 경우 - DataSourceTransactionManager를 스프링컨테이너에 빈으로 등록시킨다. 
  • tx:annotation-driver을 작성하고, transaction-manager로 txManager id를 입력한다. 
    • @Transactional 어노테이션을 활성화해서 @Transactional이 부착된 객체의 모든 메소드가 실행될 때 마다 spring이 트랜잭션 처리를 지원한다.
    • @Transactional 어노테이션은 인터페이스, 클래스, 메소드에 부착할 수 있다. 
      • 인터페이스에 부착하면, 해당 인터페이스를 구현한 객체의 모든 메소드가 실행될 때마다 트랜잭션 처리가 지원된다. 
      • 클래스에 부착하면, 해당 클래스로 생성된 객체의 모든 메소드가 실행될 때마다 트랜잭션 처리가 지원된다. 
      • 메소드에 부착하면, 해당 메소드가 실행될 때마다 트랜잭션 처리가 지원된다. 
      • 메소드 > 클래스 > 인터페이스의 순서로 우선순위가 높다.
      •  만약, 클래스와 메소드에 @Transactional 어노테이션이 모두 부찯되어 있으면, 메소드에 부착된 어노테이션의 설정에 맞게 트랜잭션이 작동하게 된다. 
               거의 대부분 default의 특징을 따르는게 일반적이다. 
      • transaction-manager="txManager" 속성값은 스프링 컨테이너에 등록시킨 트랜잭션 매니저 객체의 빈 아이디를 지정한다.
      •   <tx:annotation-driven transaction-manager="txManager"/>
    • namespace에서 tx를 클릭한다. 
    • 그리고 등록한다. 
    • 모든 service위에 @Transational을 붙인다. 
  • All or nothing으로 트랜잭션처리가 완료되었다. 
  • 하나의 메소드는 하나의 트랜잭션 단위이다. 
  • 부분적이 성공이 일어나서는 안된다. 
  • insert메소드 실행시점이 아닌 메소드를 전체적으로 실행하고, 예외처리시에는 Rollback, 예외가 발생되지 않으면 commit을 진행한다. 
  • auto로 일어나는 트랜잭션을 멈추고 선언적인 트랜잭션을 처리한다. 

처리방법

  • 메소드가 실행되면 트랜잭션 매니져가 실행된다. 
  • BasicDataSource를 참조하는 트랜잭션 동기화 저장소안에 실행되는 객체들을 넣는다. 
  • 그리고 오류가 발생되면 rollback메소드가 일어나고 오류가 없으면 commit메소드가 실행된다. 
    • 커넥션 동기화 저장소에서 커넥션을 저장한다. 
    • 커넥션 동기화 저장소가 존재하지 않으면 커넥션 풀에서 꺼내온다. 
  • 트랜잭션매니저는 서비스메소드의 수행문 실행중 DataAccessException이나 RuntimeException이 발생했으면 Rollback()실행, 예외가 발생하지 않으면 commit()을 실행한다. 
    • 언제나 전체 취소와 전체 반영만 한다. 
    • 어쨋거나 트랜잭션이 하나의 커넥션으로 실행된다. 동기화저장소의 1개로

ThreadLocal<T>클래스가 존재한다. 

  • insert시에 항상 Connection을 담고, Connection dataSource에서 객체를 꺼내야한다.
  • 그러나 그런 작업은 같은 connection을 꺼낼 수 없고, 클래스 내부에 전체적인 connection을 꺼내서 매개변수로 받아야한다. 
  • 그런작업은 반복적인 작업으로  ThreadLocal<T>을 사용한다. 
    • ThreadLocal<Integer> threadId = new ThreadLocal<Connection>(){
      protected Connection initialValue(){
      return con;
      }
      } //익명객체로 만들어서 넣으면 따로 전해줄 필요가 없다. 
      원하는 객체가 반환되게 만들어준다. 
  • 트랜잭션 저장소는 이 클래스로 만들어져있다. 
  • 담아두면 호출하는 메소드에서 꺼내갈 수 있다. 
반응형
Comments