사용자 도구

사이트 도구


springframework:abstractroutingdatasource

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판 이전 판
다음 판
이전 판
springframework:abstractroutingdatasource [2014/07/19 15:58]
kwon37xi [주의할 점]
springframework:abstractroutingdatasource [2015/12/07 13:26] (현재)
kwon37xi [Shard DataSource 구분자]
줄 8: 줄 8:
     * [[http://forum.springsource.org/showthread.php?104767-MyBatis-AbstractRoutingDataSource|MyBatis + AbstractRoutingDataSource]]     * [[http://forum.springsource.org/showthread.php?104767-MyBatis-AbstractRoutingDataSource|MyBatis + AbstractRoutingDataSource]]
  
-===== 주의할 점 ===== +===== Shard DataSource 구분자 ===== 
-  * AbstractRoutingDataSource를 사용할 경우 Transaction 처리에 주의해야 한다. DB가 변경되는 매 요청마다 트랜잭션을 안 걸어주면 한번 요청에 여러 DB접속이 필요할 경우 최초의 connection을 재사용하기 때문에 여러 DB 접속이 안된다.+  * Shard DataSource 구분자를 Enum으로 만들자. 
 +  * 개발을 하다보면 Shard 전체를 하나씩 돌면서 뭔가 처리하거나 하는 일이 생기는데, 그때 enum을 루프돌면 된다. 
 +  * 데이터 소스 구분자는 [[https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html|ThreadLocal]] 등으로 현재 요청 쓰레드에 대한 상태를 유지하고 있어야 한다.<code java> 
 +// ThreadLocal로 데이터 소스 구분자 보관 예제 
 +// 다른 예제들에서는 static 메소드로 구현했지만 그 경우 모의 객체 기반 단위 테스트 작성이 어려워진다. 
 +// Bean 으로 생성할 수 있도록 static을 사용하지 않게 하는 것이 좋아보인다. 
 +public class CustomerContextHolder { 
 + 
 +   private final ThreadLocal<CustomerType> contextHolder =  
 +            new ThreadLocal<CustomerType>(); 
 +  
 +   public void setCustomerType(CustomerType customerType) { 
 +      Assert.notNull(customerType, "customerType cannot be null"); 
 +      contextHolder.set(customerType); 
 +   } 
 + 
 +   public CustomerType getCustomerType() { 
 +      return (CustomerType) contextHolder.get(); 
 +   } 
 + 
 +   // 쓰레드가 종료될 때(특히 웹 애플리케이션의 경우 쓰레드 pool로 공유되기 때문에) 기존 데이터 clear가 필요하다. 
 +   public void clearCustomerType() { 
 +      contextHolder.remove(); 
 +   } 
 +
 +</code> 
 +  * 웹 애플리케이션의 경우 Thread Pool로 쓰레드가 공유되기 때문에, Request 종료 시점에 해당 쓰레드의 컨텍스트를 clear 해주는 filter나 interceptor를 두는 것이 좋다. 
 + 
 +===== Template/Callback 패턴을 통한 Datasource 지정 ===== 
 +  * 위의 ''CustomerContextHolder''를 통해 DataSource를 지정하고, 해제하는 것을 처리하지 않아 오류가 발생할 수 있다. 
 +  * 이를 위해 Template/Callback 패턴으로 Template 메소드가 DataSource Key를 인자로 받아 자동으로 ''CustomerContextHolder''를 초기화하고, Callback 메소드 실행후 초기화를 해주는 패턴으로 가면 좋다. 
 + 
 +===== 트랜잭션 관련 주의할 점 ===== 
 +  * AbstractRoutingDataSource를 사용할 경우 Transaction 과 DataSource의 타입 지정 타이밍 처리에 주의해야 한다. 
 +    * Transaction이 시작되기 전에(보통은 ''@Transactional''이 걸리기 전)에 먼저 사용할 DB를 지정하는 작업이 선행돼야 한다. 
 +  * DB가 변경되는 매 요청마다 트랜잭션을 안 걸어주면 한번 요청에 여러 DB접속이 필요할 경우 최초의 connection을 재사용하기 때문에 여러 DB 접속이 안된다.
   * 따라서 **꼭 트랜잭션을 걸어주고, 각 호출이 서로 다른 Connection을 사용할 수 있도록** 해야한다.(일반적으로 Connection은 TransactionManager가 관리한다)   * 따라서 **꼭 트랜잭션을 걸어주고, 각 호출이 서로 다른 Connection을 사용할 수 있도록** 해야한다.(일반적으로 Connection은 TransactionManager가 관리한다)
     * 트랜잭션 내부에서 다른 트랜잭션 호출시 커넥션 변경을 유발하라면 Propagation 규칙을 잘 적용해야 한다.     * 트랜잭션 내부에서 다른 트랜잭션 호출시 커넥션 변경을 유발하라면 Propagation 규칙을 잘 적용해야 한다.
     * ''Propagation.REQUIRES_NEW/NEVER/NOT_SUPPORTED'' 등을 조합할 수 있어야 한다.     * ''Propagation.REQUIRES_NEW/NEVER/NOT_SUPPORTED'' 등을 조합할 수 있어야 한다.
springframework/abstractroutingdatasource.1405753088.txt.gz · 마지막으로 수정됨: 2014/07/19 15:58 저자 kwon37xi