@Transactional 주석은 어디에 속합니까?


528

클래스 및 / 또는 해당 메소드 @Transactional에 배치해야합니까 DAO, 아니면 DAO 객체를 사용하여 호출하는 서비스 클래스에 주석을 추가하는 것이 더 낫습니까? 아니면 두 "레이어"에 주석을 추가하는 것이 합리적입니까?

답변:


537

거래는 서비스 계층에 속한다고 생각합니다. 작업 단위 및 사용 사례에 대해 알고있는 사람입니다. 단일 트랜잭션에서 함께 작동해야하는 여러 DAO를 서비스에 주입 한 경우 정답입니다.


동의합니다. 때로는 중요하지 않지만 때로는 Hibernate 세션이 while 트랜잭션에 걸쳐 있기 때문에 이점을 얻을 수 있습니다. 따라서로드 된 모든 오브젝트가 1 레벨 캐시에 있으므로 오브젝트를 다시 세션에 다시 연결할 필요가없고 지연로드됩니다. 퍼지없이 속성 기능.
dma_k

5
글로벌 트랜잭션이 @Transactional (propagation = Propagation.REQUIRED) 중 하나 이상으로 구성 될 수 있습니까? 또는 @Transactional은 항상 트랜잭션의 경계입니까? 나는 문서에서 그것을 확신하지 못하지만, @Transactional 메소드와 내부에서 실행되는 모든 것들로 구성된 트랜잭션조차 만들 수있는 것처럼 보인다
lisak

1
예, 가장 바깥 쪽 @Transactional은 Propagation.REQUIRED가 설정되어 있으면 트랜잭션의 경계가되는 것입니다.
duffymo


309

일반적으로 거래는 일반적으로 서비스 수준에서 시작된다는 진술에 동의합니다 (물론 필요한 세분성에 따라 다름).

그러나 @Transactional(propagation = Propagation.MANDATORY)그 동안 발신자에서 거래를 시작하지 않은 오류를 훨씬 쉽게 감지 할 수 있기 때문에 DAO 레이어 (및 거래를 시작할 수 없지만 기존 레이어가 필요한 다른 레이어)에 추가하기 시작했습니다 ( 예를 들어 서비스). DAO에 필수 전파로 주석이 달린 경우 메소드가 호출 될 때 활성 트랜잭션이 없다는 예외가 발생합니다.

또한이 주석에 대한 모든 bean (bean post processor) @Transactional을 확인하고 서비스 계층에 속하지 않는 bean에서 Mandatory 이외의 전파 가있는 주석 이 있으면 실패하는 통합 테스트가 있습니다. 이렇게하면 잘못된 계층에서 트랜잭션을 시작하지 않습니다.


3
이것이 dao impl의 dao (인터페이스) 레이어에서 수행되어야합니다. 레이어 또는 둘 다?
Johan

3
이 토론에 맞는지 모르겠지만 비 쓰기 작업의 dao impl에 @Transactional (readOnly = true)을 추가 할 수 있습니다.
maxivis

10
@Johan Spring은 인터페이스 대신 구현 클래스에 트랜잭션 주석을 넣을 것을 권장합니다.
Mathias G.

나는이 아이디어가 정말 마음에 들어 내 프로젝트도 시도하고있다
Thomas Einwaller

1
Lemme는 내가 이해하는지 알아 ... @Transactional서비스 구현 클래스를 입어야한다고 말하고 @Transactional(propagation = MANDATORY)DAO (리포지토리) 클래스 구현을 입어야한다고 말하고 있습니까?
John Henckel

93

트랜잭션 주석은 분리 할 수없는 모든 작업 주위에 배치해야합니다.

예를 들어 전화는 "비밀번호 변경"입니다. 그것은 두 가지 작업으로 구성됩니다

  1. 비밀번호를 변경하십시오.
  2. 변경 사항을 감사하십시오.
  3. 비밀번호가 변경된 클라이언트에게 이메일을 보냅니다.

따라서 위의 감사가 실패하면 암호 변경도 실패해야합니까? 그렇다면 트랜잭션은 약 1과 2 여야합니다 (서비스 계층에서도). 전자 메일이 실패하는 경우 (아마도 이것에 대해 안전 장치가 있어야 실패하지 않을 것입니다) 변경 암호와 감사를 롤백해야합니까?

이것들은 어디에 넣을지를 결정할 때 물어봐야 할 질문들 @Transactional입니다.


41

전통적인 Spring 아키텍처에 대한 정답은 다른 사람들이 이미 설명한 이유로 서비스 클래스에 트랜잭션 의미 체계를 배치하는 것입니다.

Spring에서 떠오르는 트렌드는 도메인 기반 디자인 (DDD)에 대한 것입니다. Spring Roo 는 트렌드를 잘 보여줍니다. 아이디어는 도메인 객체 POJO 를 일반적인 Spring 아키텍처보다 훨씬 더 풍부하게 만들고 (일반적으로 빈혈이 없음 ), 특히 도메인 객체 자체에 트랜잭션 및 지속성 의미를 두는 것입니다. 필요한 모든 것이 간단한 CRUD 작업 인 경우 웹 컨트롤러는 도메인 개체 POJO에서 직접 작동하며 (이 컨텍스트에서 엔터티로 작동하고 있음) 서비스 계층이 없습니다. 도메인 객체간에 조정이 필요한 경우 다음과 같은 서비스 Bean 핸들을 가질 수 있습니다.@Transaction전통에 따라. 도메인 오브젝트에서 트랜잭션 전파를 설정하여 도메인 오브젝트가 REQUIRED서비스 Bean에서 시작된 트랜잭션과 같은 기존 트랜잭션을 사용하도록 할 수 있습니다.

기술적으로이 기술은 AspectJ 및를 사용 <context:spring-configured />합니다. Roo는 AspectJ 인터 타입 정의를 사용하여 엔티티 시맨틱 (트랜잭션 및 지속성)을 도메인 객체 (기본적으로 필드 및 비즈니스 메소드)와 분리합니다.


38

일반적인 경우는 서비스 계층 수준에 주석을 달지만 실제로는 요구 사항에 따라 다릅니다.

서비스 계층에 주석을 달면 DAO 수준에서 주석을 달 때보 다 트랜잭션이 길어집니다. 예를 들어 동시 트랜잭션은 서로의 변경 사항을 볼 수 없으므로 트랜잭션 격리 수준에 따라 문제를 해결할 수 있습니다. 반복 가능한 읽기.

DAO에 주석을 달면 서비스 계층이 제공하는 기능이 단일 (롤백 가능) 트랜잭션으로 수행되지 않는다는 단점이 있으므로 트랜잭션을 최대한 짧게 유지합니다.

전파 모드가 기본값으로 설정된 경우 두 레이어에 주석을다는 것은 의미가 없습니다.


31

레이어 @Transactional에 배치하고 예외를 @Service설정 하고 트랜잭션을 추가로 최적화합니다.rollbackForreadOnly

기본적으로 (확인되지 ​​않은 예외) @Transactional만 찾고 RuntimeException롤백을 Exception.class(확인 된 예외) 로 설정 하면 예외가 롤백됩니다.

@Transactional(readOnly = false, rollbackFor = Exception.class)

확인 된 예외와 확인되지 않은 예외를 참조하십시오 .


17

아니면 두 "레이어"에 주석을 추가하는 것이 합리적입니까? -DAO에서 전파가 "필수"인 서비스 계층에서 DAO 방법이 항상 호출 (전파)되도록하려면 서비스 계층과 dao 계층 모두에 주석을 추가하는 것이 이치에 맞지 않습니다. 이것은 DAO 메소드가 UI 계층 (또는 컨트롤러)에서 호출되는 것을 제한합니다. 또한-특히 DAO 계층을 단위 테스트 할 때 DAO에 주석을 달면 트랜잭션 기능에 대해 테스트됩니다.


이 작업을 수행하면 중첩 트랜잭션이 발생하지 않습니까? 그리고 그와 관련된 모든 미묘한 문제는 무엇입니까?
HDave

11
아니요, JPA에는 중첩 트랜잭션이 없습니다. DAO에 도달했을 때 이미 거래 중이라면 거래가 계속됩니다.
fool4jesus

4
를 사용하면 중첩 트랜잭션이 발생할 수 있습니다 propagation=Propagation.REQUIRES_NEW. 그렇지 않으면 propogation = mandatory를 포함한 대부분의 경우 DAO는 서비스 계층에서 시작한 기존 트랜잭션에 참여합니다.
dan carter


15

데이터베이스 레벨의 트랜잭션

주로 @TransactionalDAO에서 메소드 수준에서만 사용 했으므로 구성은 메소드 / 특히 기본값을 사용하여 (필수) 구성 할 수 있습니다

  1. 데이터 가져 오기 (select ..)를 얻는 DAO의 방법- @Transactional 이것을 필요로하지 않아도 트랜잭션 인터셉터 / 및 AOP 프록시로 인해 오버 헤드가 발생할 수 있습니다.

  2. 삽입 / 업데이트를 수행하는 DAO의 메소드는 @Transactional

transactional 에 대한 아주 좋은 블로그

응용 프로그램 수준-
비즈니스 논리에 트랜잭션을 사용하고 있습니다. 예기치 않은 오류가 발생하면 롤백하고 싶습니다.

@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){

    try {    
        //service logic here     
    } catch(Throwable e) {

        log.error(e)
        throw new MyApplicationException(..);
    }
}

6
약 한 아주 좋은 기사 Transactional에서Java
오크

11

일반적으로 서비스 계층에서 거래를해야합니다.

그러나 앞에서 언급했듯이 작업의 원자 성은 주석이 필요한 위치를 알려줍니다. 따라서, 최대 절전 모드와 같은 프레임 워크를 사용하는 경우 개체에 대한 단일 "저장 / 업데이트 / 삭제 / ... 수정"작업이 여러 테이블의 여러 행을 수정할 수있는 가능성이 있습니다 (개체 그래프를 통한 계단식으로 인해). 물론이 특정 DAO 방법에 대한 트랜잭션 관리도 있어야합니다.


10

@Transactional분리 할 수없는 모든 작업에 주석을 달아야합니다. @Transactional트랜잭션 전파 사용 은 자동으로 처리됩니다.이 경우 현재 메소드에서 다른 메소드를 호출하면 해당 메소드에 진행중인 트랜잭션에 참여할 수있는 옵션이 있습니다.

예를 들어 보자.

우리는이 모델의 예를 가지고 CountryCity. 관계형 매핑 CountryCity모델은 Country여러 도시를 가질 수 있으므로 매핑은

@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;

여기서 국가는 여러 도시를 가져 와서 매핑했습니다 Lazily. 그래서 여기의 역할 온다 @Transactinal우리가 다음 우리는 국가 개체의 모든 데이터를 얻을 것이다 데이터베이스에서 국가 개체를 검색하지만 우리는 도시를 가져 오는 있기 때문에 도시의 설정을받지 않습니다 때를 LAZILY.

//Without @Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //After getting Country Object connection between countryRepository and database is Closed 
}

국가 개체에서 도시 집합에 액세스하려는 경우이 집합 만 생성 된 집합의 개체가 집합의 값을 가져 오는 데이터로 초기화되지 않기 때문에 집합에서 null 값을 얻습니다 @Transactional.

//with @Transactional
@Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
   Object object = country.getCities().size();   
}

따라서 기본적 @Transactional으로 서비스는 엔드 포인트와의 연결을 닫지 않고도 단일 트랜잭션에서 여러 호출을 할 수 있습니다.


2
매우 유익한, 감사합니다! 내가 찾던 것, @Transactional실제로 무엇이 있는지에 대한 설명
CybeX

6

서비스 계층에있는 것이 좋습니다. 이것은 어제 나간 기사 중 하나에 명확하게 설명되어 있습니다! 확인할 수 있는 링크 는 다음과 같습니다 .


5

여기에 이미지 설명을 입력하십시오

@Transactional는 비즈니스 로직을 포함로 서비스 계층에 사용되어야한다. DAO 계층에는 일반적으로 데이터베이스 CRUD 작업 만 있습니다.

// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

스프링 문서 : https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html


5

서비스 계층은 @Transactional여기에 존재하는 대부분의 비즈니스 논리와 같이 주석 을 추가하는 가장 좋은 장소 이며 세부 수준의 사용 사례 동작을 포함합니다.

서비스를 DAO에 추가하고 서비스에서 우리는 2 개의 DAO 클래스를 호출한다고 가정합니다. 하나는 실패하고 다른 성공입니다.이 경우 @Transactional서비스 중 하나 가 아니면 하나의 DB는 커밋하고 다른 하나는 롤백합니다.

따라서이 주석을 현명하게 사용하고 서비스 계층에서만 사용하는 것이 좋습니다.

Github 프로젝트-Java-algos


ObjectOptimisticLockingFailureException과 같은 예외는 트랜잭션이 완료된 후에 만 ​​발생합니다. 메일 서비스와 같은 다른 작업을 위해 별도의 스레드가있는 경우이 디자인은 완전히 실패합니다. 우리는 지금 고통 받고 있습니다. 왼쪽 솔루션 만 AOP입니다.
Nabin Kumar Khatiwada

4

먼저 트랜잭션 을 어디에서 사용 해야하는지 정의 해 봅시다 .

정답은-하나의 원자 작업으로 일련의 작업이 함께 완료되거나 작업 중 하나가 실패하더라도 변경되지 않도록해야 할 때입니다.

비즈니스 로직을 서비스에 넣는 것은 잘 알려진 관행입니다. 따라서 서비스 메소드에는 단일 논리 작업 단위로 수행해야하는 다른 조치가 포함될 수 있습니다. 그렇다면 그러한 방법은 트랜잭션 으로 표시해야합니다 . 물론 모든 방법에 이러한 제한이 필요한 것은 아니므로 전체 서비스를 transactional 로 표시 할 필요는 없습니다 .

그리고 @Transactional이 메서드 성능을 저하시킬 수 있다는 점을 잊지 마십시오 . 전체 그림을 보려면 트랜잭션 격리 수준을 알아야합니다. 그것이 필요하지 않은 곳에서 @Transactional 사용을 피하는 데 도움이 될 수 있습니다 .


3

@Transactional 을 DAO와 서비스 계층 사이의 별도 중간 계층에 유지하는 것이 좋습니다 . 롤백이 매우 중요하므로 모든 DB 조작을 중간 계층에 배치하고 비즈니스 논리를 서비스 계층에 작성할 수 있습니다. 중간 계층은 DAO 계층과 상호 작용합니다.

ObjectOptimisticLockingFailureException 과 같은 여러 상황에서 도움이됩니다. 이 예외는 거래가 끝난 후에 만 ​​발생합니다. 따라서 중간 계층에서는 잡을 수 없지만 이제 서비스 계층에서는 잡을 수 있습니다. 서비스 계층에 @Transactional이 있으면 불가능합니다. 컨트롤러를 잡을 수는 있지만 컨트롤러는 가능한 깨끗해야합니다.

모든 저장, 삭제 및 업데이트 옵션을 완료 한 후 별도의 스레드로 메일 또는 SMS를 보내는 경우 중간 계층에서 트랜잭션이 완료된 후 서비스에서이를 수행 할 수 있습니다. 서비스 계층에서 @Transactional을 언급하면 ​​트랜잭션이 실패하더라도 메일이 전송됩니다.

따라서 중간 @Transaction 레이어를 사용하면 코드를보다 쉽고 효율적으로 처리 할 수 ​​있습니다. 그렇지 않으면 DAO 계층에서 사용하는 경우 모든 작업을 롤백하지 못할 수 있습니다. 서비스 계층에서 사용 하는 경우 경우에 따라 AOP (Aspect Oriented Programming) 를 사용해야 할 수도 있습니다 .


2

이상적으로 서비스 계층 (Manager)은 비즈니스 로직을 나타내므로.로 주석을 @Transactional달아야합니다. 서비스 계층은 다른 DAO를 호출하여 DB 작업을 수행 할 수 있습니다. 서비스 방법에 N 개의 DAO 작업이있는 상황을 가정 해 봅시다. 첫 번째 DAO 작업이 실패한 경우 다른 작업이 여전히 통과되어 일관되지 않은 DB 상태가됩니다. 서비스 계층에 주석을 달면 이러한 상황에서 벗어날 수 있습니다.



1

@Transactional컨트롤러 계층 ( @Controller) 및 DAO 계층 ( @Repository) 에 대한 서비스 계층 호출, 즉 데이터베이스 관련 작업 을 사용하여 호출되는 서비스 계층에서 사용 합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.