Spring boot - 서비스 추상화

원종서·2021년 12월 30일
0

spring

목록 보기
11/12

5 서비스 추상화

트렌젝션: 더 이상 나눌 수 없는 단업 단위. (원자성)

5.2.2 트랜잭션 경계설정

SQL 명렁을 처리하는 경우 DB가 트랜잭션을 보장해준다.
하지만 2개의 SQL을 하나의 트랜잭션으로 자동 묶어주진 않는다.

JDBC 트랜잭션의 트랜잭션 경계설정

트랜잭션이 시작되고 끝나는 위치를 트랜잭션 경계라고 한다.

Connection c = dataSource.getConnection();

c.setAutoCommit(false);

try{
 PreparedStatement st1= c.preparedStatement("update .... ");
 st1.excuteUpdate();
 
 PreparedStatement st2= c.preparedStatement("delete .... ");
  st2.excuteUpdate();
  
  c.commit();
  }
  catch(Exception e){
  	c.rollback();
   }
   c.close();
}

트랜잭션의 시작과 종료는 Connection을 가져와 사용하다가 닫는 사이에 일어난다.

setAutoCommit(false) 로 트랜잭션 시작을 선언하고 commit() 또는 rollback()으로 트랜잭션을 종료하는 작업을 트랜잭션의 경계설정 이라고 한다.

이렇게 하나의 DB 커넥션 안에서 만들어지는 트랜잭션을 로컬 트랜잭션 이라고 한다.


트랜잭션 동기화

: UserService에서 트랜잭션을 시작하기 위해 만든 Connection 오브젝트를 특별한 저장소에 보관해두고, 이후에 호출되는 DAO의 메소드에서는 저장된 Connection을 가져다가 사용하는 것이다.

1) UserService는 Connection을 생성하고 2) 이를 트랜잭션 동기화에 저장소에 저장해두고 Connection의 setAutoCommit(false) 를 호출해 트랜잭션을 시작시킨 후에 본격젹으로 DAO의 기능을 이요하기 시작함. 3) 첫번째 update()메소드가 호출되고, update메소드 내부에서 이용하는 jdbcTemplate 메소등서는 가장 먼저 4) 트랜잭션 동기화 저장소에 현재 시작된 트랜잭션을 가진 Connection 오브젝트가 이쓴지를 확인한다.

위의 방법을 사용하면 파라미터를 통해 일일이 커넥션 오브젝트를 전달할 필요가 업어진다.

트랜잭션 동기화 적용

멀티 스레드 환경에서도 안전한 트랜잭션 동기화 방법을 구현하는 것은 간단하지 않는데, 다행이도 스프링은 jdbcTemplate과 더불어 이런 트랜잭션 동기화 기능을 지원하는 간단한 유틸리티 메서드를 제공한다.

public void upgradeLevels() throws SQLException {
        // 트랜잭션 동기화 관리자를 이용해 동기화 작업을 초기화한다.
        TransactionSynchronizationManager.initSynchronization();

		// DataSourceUtils을 사용하는 이유는 커넥션 오브젝트의 생성과 트랜잭션 동기화에 사용하다록, 저장소에 바인딩 해주기 ㄸ문.
        Connection c= DataSourceUtils.getConnection(dataSource);
        c.setAutoCommit(false);

        try{
            List<User> users = dao.getAll();
            for(User user : users){
              if(canUpgradeLevel(user))
                  upgradeLevel(user);
            }
            c.commit();
        }catch (Exception e){
            c.rollback();
            throw  e;
        }
        finally {
            DataSourceUtils.releaseConnection(c,dataSource);
            TransactionSynchronizationManager.unbindResource(this.dataSource);
            TransactionSynchronizationManager.clearSynchronization();
        }
    }

글로벌 트랜잭션

여러개의 DB를 트랜잭션 하기 위해서는 글로벌 트랜잭션을 사용해야한다.
글로벌 트랜잭션을 지원하는 트랜잭션 매니저를 지원하기 위한 API , JTA(Java TransAction API)를 제공하고 있다.

JTA를 이용해 트랜잭션 매니를 활용하면 여러 개ㅣ DB나 메시징 서버에 대한 작업을 하나의 트랜잭션으로 통합하는 분산 트랜잭션 또는 글로벌 트랜잭션이 가능하다.

스프링이 제공하는 트랜잭션 경계설정을 위한 추상 인터페이스는 PlatformTransactionManager 이다.

로컬 트랜잭션을 이용하라면 PlatformTransactionManager를 구현한 DataSourceTransactionManager 을 사용하면 된다.

public void upgradeLevels() throws SQLException {
        // JDBC 트랜잭션 추상 오브젝트 생성
        PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);

        TransactionStatus status=  transactionManager.getTransaction(new DefaultTransactionDefinition());

        try{
            List<User> users = userDao.getAll();
            for(User user : users){
              if(canUpgradeLevel(user))
                  upgradeLevel(user);
            }
            transactionManager.commit(status);
        }catch (Exception e){
            transactionManager.rollback(status);
            throw  e;
        }
    }

위의 코드에서 로컬 트랜잭션에서 글로벌 트랜잭션으로 변경하기 위해서는

    PlatformTransactionManager transactionManager = new JTATransactionManager(dataSource); 

로 바꿔주기만 하면 된다.

0개의 댓글