2009-06-15 5 views
4

스프링, jdbc 및 aop을 사용하여 트랜잭션이있는 다중 스레드 된 Java 응용 프로그램을 m 패키지의 n 클래스로 모두 데이터베이스 변환에 사용한다고 가정하십시오. 이제 한 트랜잭션 내에서 임의의 클래스 집합 범위를 지정할 필요가 있다고 가정 해 봅시다. 또한 호출 될 때 트랜잭션을 커밋하는 범위 내에 항상 하나의 클래스 T가 있습니다.AOP, Spring 및 트랜잭션 범위 지정

명확성을 위해 예를 들어 보겠습니다. 패키지 A, B, Z 및 클래스 A.Foo, B.Bar 및 Z.T가 제공됩니다. 각 클래스의 다음 인스턴스가 호출됩니다 (다른 클래스가있는 다른 호출자가 호출 할 수 있음). A.Foo, B.Bar, A.Foo, Z.T 트랜잭션은 Z.T가 호출 된 후에 만 ​​커밋됩니다. Z.T가 관련되지 않으면 어떤 이유로 든 트랜잭션이 커밋되지 않습니다.

인스턴스는 서로 호출 할 수 있으며 이미 언급했듯이 단일 인스턴스 (예 : 서비스 계층)에서 모든 인스턴스를 호출하는 공통 진입 점이 없으므로 Spring의 트랜잭션 태그를 쉽게 지정할 수 있습니다.

이제 질문 : 측면을 사용하여이 문제를 해결할 수 있습니까? 그렇다면 기본 접근 방식은 무엇입니까? 감사합니다. .

+0

웹 컨테이너 안에 있는지, 그리고 웹 요청의 일부로 거래가 항상 발생하고 요청 당 여러 건의 거래가 있는지 여부를 명확히 할 수 있습니까? – skaffman

+0

거래는 웹 프런트 엔드를 사용하는지 여부를 알지 못하거나주의해서는 안됩니다. 작업 단 위를 알고있는 서비스 계층이며 트랜잭션이 선언 된 곳입니다. – duffymo

+0

웹 컨테이너 안에 있지 않습니다. 응용 프로그램은 독립 실행 형으로 실행됩니다. duffymo가 맞다. 웹 프론트 엔드는이 경우 중요하지 않아야한다. (만약 내가 존재하는 문제를 바꾸지 않는다면) –

답변

2

단일 진입 점은 필요하지 않지만 재진입 호출이 동일한 트랜잭션에 참여할 수 있도록 트랜잭션 인터셉터를 모든 진입 점에 적용 할 수 있어야합니다. 그렇게 할 수 있다고 가정하면 ThreadLocal 플래그와 사용자 정의 org.springframework.transaction.support.TransactionSynchronization 구현을 사용하여이를 수행 할 수 있습니다.

커밋이 안전 할 때 ThreadLocal 플래그를 설정하려면 Z.T를 수정하십시오. PlatformTransactionManager에서 호출 된 TransactionSynchronization.beforeCommit() 구현에서 플래그를 확인하고이를 사용하여 커미트가 진행되도록 허용할지 여부를 결정할 수 있습니다. 플래그가 없으면 RuntimeException을 던져 롤백을 강제 실행할 수 있습니다.

다른 거래 유형 (설명 된 3 가지 조정 클래스가 포함되지 않음)이 있다면주의해야합니다. 부주의로 롤백되지 않도록해야합니다. 이렇게하려면 다른 ThreadLocal 플래그를 통해 A.Foo, B.Bar 및 Z.T에서이 "특수 트랜잭션"을 플래그 한 다음 위에서 언급 한 beforeCommit() 메소드의 보호 절에서 해당 플래그를 확인하십시오. 가짜 코드 :


void beforeCommit() { 
    if in special transaction 
    if commit flag not set 
     throw new RuntimeException("cancel transaction") 
    end if 
    end if 
end 

분명히 이것은 해킹이며 나는 그린 필드 시스템에서하는 것을 옹호하지 않을 것입니다. :).

+0

그것이 제가 작업 할 수있는 출발점입니다. 유용한 답변 주셔서 감사합니다. –

1

스프링의 관용구는 작업 단위와 관계형 데이터베이스를 처리하는 지속성 인터페이스를 알고있는 서비스 인터페이스를 갖는 것이 좋습니다. 서비스 인터페이스의 메소드는 유스 케이스와 밀접하게 맵핑되어야한다. 서비스 구현은 유스 케이스의 목표를 달성하는 데 필요한 모든 모델 및 지속성 패키지와 클래스를 알고 있습니다.

"인스턴스는 서로 호출 할 수 있으며 이미 언급 한 것처럼 서비스 인스턴스와 같은 단일 인스턴스에서 모든 인스턴스를 호출하는 공통 진입 점이 없으므로 Spring의 트랜잭션 태그를 쉽게 지정할 수 있습니다."

이 문장은 당신이 봄의 관용구에 너무 쉽게 빌려주지 않는 방식으로 일을한다는 것을 말해줍니다. 원하는 것을 정확히 말하기는 어렵지만 Spring에서 권장하는 가장 중요한 두 레이어를 버리는 것처럼 들립니다. 곡물에 맞서기가 어려울 경우 재 작업이 필요한 디자인 일 것입니다.

"... 다른 클래스가있는 다른 발신자 ..."- 발신자별로 개별적으로 거래를 신고해야 할 수 있습니다.

Spring AOP 또는 AspectJ로 aspect를 사용하여 XML 설정으로 트랜잭션을 선언 할 수있다. 봄 2.5 이상에서는 XML 구성을 선호하는 경우 특수 효과를 사용할 수있는 옵션을 제공합니다.

설명이 매우 혼란 스럽습니다. 어쩌면 그것도 당신이 어려움을 겪고있는 이유의 일부입니다. 나는 다시 생각해 보거나 명료하게 말할 것입니다.

봄 거래와 당신이 그것을 할 수 있지만 "해킹"의 비트 수 있습니다 AOP
+0

저는 기존의 사내 프레임 워크를 다루므로, Spring의 관용구에 대한 리팩토링은 기껏해야 어렵습니다. 주어진 설명은 일반적인 내용이지만 혼란은 보이지 않습니다. 세 가지 다른 패키지에 걸쳐있는 세 가지 다른 클래스의 세 가지 인스턴스 인 a, b, z는 응용 프로그램 내 어디에서나 호출 할 수 있으며 함께 단일 트랜잭션을 형성합니다. 트랜잭션의 세 번째 클래스가 호출되면 트랜잭션은 커밋됩니다. 따라서 a는 호출되고 b는 호출되고 c는 호출 됨 -> commit. B가 호출되면 a는 호출되고 c는 호출되지 않고 커밋되지 않습니다. A는 호출되고 C는 호출되고 커밋됩니다. –

+0

"유산"? 봄은 그리 오래되지 않았습니다. 이것을 시작한 사람들처럼 봄은 몰랐다. 스프링으로 리팩토링하는 것이 그렇게 어렵다고 믿기가 힘듭니다. 어떤 객체는 상호 작용하는 인스턴스를 생성해야합니다. 객체 소유자는 트랜잭션을 소유해야합니다. "응용 프로그램 내부의 어디에서든지"- 엉망인 것처럼 들립니다. 미안, 너를 도울 수 없어. – duffymo

+0

나는 이것을 말할 수있다. 프레임 워크는해야 할 일을하고이 점에서 잘 설계되어있다. 스프링 수용 관용구로 바꾸는 것은 가능하지만 너무 많은 작업이 가능할 것입니다. –

0

...

당신은 모든 진입 점에서 트랜잭션의 시작을 넣어해야합니다 - 당신이 할 수있는 트랜잭션을 시작할 때만 커밋하고 커밋 여부를 제어하려면이 내부에 두 번째 측면이 필요합니다.

이제 트랜잭션을 롤백하는 유일한 방법은 트랜잭션 경계에서 예외를 throw하는 것입니다. 따라서 커밋의 원인이 될 Z 영역에 들어가면 "내부"속성이 발견되어 throw되지 않는 스레드 로컬 (또는 aspect를 통해 가능)에 뭔가를 넣어야합니다. 트랜잭션을 롤백하는 예외.Z를 입력하지 않으면 스레드 로컬은 플래그를 얻지 못하고 내부 aspect를 거쳐 돌아갈 때 트랜잭션을 롤백하는 예외가 발생합니다. 아마도 그 예외를 삼켜 야합니다.

관련 문제