2014-08-29 5 views
1

2 데이터베이스에 액세스하려면 (필요 없음 단일 트랜잭션 동작) :봄 스위치

첫 번째 트랜잭션 관리자 :

<bean id="transactionManager" 
    class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

두 번째 트랜잭션 관리자 :

서비스 계층에
<bean id="transactionManager2" 
    class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory2" /> 
</bean> 

, 우리는 ID를 가져옵니다과 DTO를 반환하는 방법을 가지고 싶습니다. 문제는 DTO가 두 데이터베이스의 데이터로 채워 져야한다는 것입니다.

  • 가 FooDao가 :

    우리는이 첫 번째 접근 시도 sessionFactory에 (의 transactionManager와 같은)를 사용을
  • BarDao : 다음과 같은 서비스를 통해 sessionFactory2 (transactionManager2 같은 sessionFactory에)

를 사용 방법 :

@Autowired 
private FooDao fooDao; 

@Autowired 
private BarDao barDao; 

@Transactional(value="transactionManager", readOnly=true) 
public FooBarDto getFoo(int id) { 
    Foo foo = fooDao.get(id); 

    return createDto(foo); 
} 

@Transactional(value="transactionManager2", readOnly=true) 
public FooBarDto createDto(Foo foo) { 
    Bar bar = barDao.get(foo.getId()); 

    FooBarDto fooBarDto = new FooBarDto(); 

    fooBarDto.setId(String.valueOf(foo.getId())); 
    fooBarDto.setA(String.valueOf(foo.getA())); 
    fooBarDto.setB(String.valueOf(foo.getB())); 
    fooBarDto.setC(String.valueOf(bar.getC())); 
    fooBarDto.setD(String.valueOf(bar.getD())); 

    return fooBarDto; 
} 

그러나이 경우 barDao 메소드에서 "현재 스레드에 대한 세션을 찾을 수 없습니다"오류가 발생합니다. 단일 트랜잭션에서 전체 작업을 수행 할 필요가 없으므로 (현재 구성을 유지하려면) JTA를 사용하지 않는 것이 좋습니다.

우리는 Propagation.REQUIRES_NEW를 사용하여 트랜잭션 전파를 구성하려고했지만 동일한 관리자의 트랜잭션에만 작동하는 것처럼 보입니다.

우리는이 두 가지 방법을 변경하고 컨트롤러에서 둘 다 (순차적으로) 호출 할 수 있지만 모든 작업을 수행하기 위해 단일 서비스 메서드를 호출하는 것이 좋습니다. 예상되는 행동을 달성 할 수있는 방법이 있습니까?


감사합니다. Ricardo Veguilla! 당신의 제안에 따라 모든 것이 이제는 잘되고 있습니다. 나는 다른 서비스 (BarService)로 가도록 만들어진 방법을 이동하고 첫 번째 서비스 (FooService)에 그것을 autowire가 :

@Service 
public class FooServiceImpl implements FooService { 

    @Autowired 
    private FooDao fooDao; 

    @Autowired 
    private BarService barService; 

    @Transactional(value="transactionManager", readOnly=true) 
    public FooBarDto getFoo(int id) { 
     Foo foo = fooDao.get(id); 

     return barService.createDto(foo); 
    } 
} 

그리고 생성 된 BarService :

@Service 
public class BarServiceImpl implements BarService { 

    @Autowired 
    private BarDao barDao; 

    @Transactional(value="transactionManager2", readOnly=true) 
    public FooBarDto createDto(Foo foo) { 
     FooBarDto fooBarDto = new FooBarDto(); 

     if (foo != null) { 
      Bar bar = barDao.get(foo.getId()); 

      fooBarDto.setId(String.valueOf(foo.getId())); 
      fooBarDto.setA(String.valueOf(foo.getA())); 
      fooBarDto.setB(String.valueOf(foo.getB())); 

      if (bar != null) { 
       fooBarDto.setC(String.valueOf(bar.getC())); 
       fooBarDto.setD(String.valueOf(bar.getD())); 
      } 
     } 

     return fooBarDto; 
    } 
} 

답변

1

당신은 barDao bacuse에는 세션을 받고되지 않습니다 당신 동일한 빈 내부에서 createDto을 호출하고 있습니다. 즉, 메소드 호출은 Spring Transacitional 프록시를 통과하지 않습니다.

스프링에서 @Transactional으로 주석 처리 된 공개 메소드가있는 bean myBeanmyBean 인스턴스가 삽입 된 다른 빈에서 호출해야합니다. 트랜잭션 지원은 프록시를 사용하여 구현되기 때문입니다. 당신은 다른 콩에 createDto 방법을 이동해야합니다 자바 (8)을 사용하는 경우

@component 
public class ForBarService { 

     @Autowired 
     private FooDao fooDao; 

     @Autowired 
     private DtoFactory dtoFactory; 

     @Transactional(value="transactionManager", readOnly=true) 
     public FooBarDto getFoo(int id) { 
     Foo foo = fooDao.get(id); 
      return dtoFactory.createDto(foo); 
     } 
} 

@Component 
public class DtoFactory { 
     @Autowired 
     private BarDao barDao; 

     @Transactional(value="transactionManager2", readOnly=true) 
     public FooBarDto createDto(Foo foo) { 
      Bar bar = barDao.get(foo.getId()); 

      FooBarDto fooBarDto = new FooBarDto(); 

      fooBarDto.setId(String.valueOf(foo.getId())); 
      fooBarDto.setA(String.valueOf(foo.getA())); 
      fooBarDto.setB(String.valueOf(foo.getB())); 
      fooBarDto.setC(String.valueOf(bar.getC())); 
      fooBarDto.setD(String.valueOf(bar.getD())); 

      return fooBarDto; 
     } 

} 
0

당신이 같은 클래스를 만들 수 있습니다

@Component 
class TransactionWrapper { 

    @Transactional 
    public <T> T doInTransaction(Supplier<T> supplier) { 
     return 
    } 

트랜잭션 컨텍스트 클래스 내부 방법 (즉 개인들)을 호출합니다.