inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

스프링 DB 2편 - 데이터 접근 활용 기술

테스트 - @Transactional

@Transactional 롤백,,?

해결된 질문

427

모깅

작성한 질문수 55

0

안녕하세요 강사님. 프로젝트 진행중에 간단한 테스트 작업 중 이상한 결과가 나와서 질문드립니다..!

@Transactional
@SpringBootTest
@ActiveProfiles("test")
class ProductListResponseDtoTest {

    @Autowired ProductRepository productRepository;

    @Test
    @DisplayName("주문 상세가 주어졌을 때 ProductListResponseDto 변환")
    public void ofWithOrderDetail() {
        Product product = Product.builder()
                .price(1000L)
                .name("빵빵이")
                .productNo("123")
                .build();
        productRepository.save(product);

        OrderDetail orderDetail = OrderDetail.builder()
                .product(product)
                .price(product.getPrice())
                .quantity(2L)
                .build();

        // when
        ProductListResponseDto result = ProductListResponseDto.of(orderDetail);

        // then
        assertThat(result).extracting("productId", "productNo", "name", "price", "quantity")
                .contains(1L, "123", "빵빵이", 1000L, 2L);
    }


    @Test
    @DisplayName("상품과 수량이 주어졌을 때 ProductListResponseDto 변환")
    public void ofWithProductAndQuantity() {
        Long quantity = 2L;

        Product product = Product.builder()
                .price(1000L)
                .name("빵빵이")
                .productNo("123")
                .build();
        productRepository.save(product);

        // when
        ProductListResponseDto result = ProductListResponseDto.of(product, quantity);

        // then
        assertThat(result).extracting("productId", "productNo", "name", "price", "quantity")
                .contains(1L, "123", "빵빵이", 1000L, 2L);

    }

}

@Transactional를 통해 각 테스트가 롤백되어 productId가 모두 1L 될 것으로 예상하였습니다.

그런데 기대와 달리 실패를 하였는데요. 첫번째 테스트(ofWithOrderDetail)의 productId의 값이 2L 되었습니다.

 

insert문과 에러 메세지입니다.

Hibernate: 
    insert 
    into
        product
        (category_id, created_at, deleted_at, discount_rate, is_own, is_subs, name, price, product_no, stock, thumb_img, updated_at, product_id) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, default)
2024-01-29T22:28:07.219+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887219 | took 4ms | statement | connection 3| url jdbc:h2:mem:~/Marketbridge
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (?,?,?,?,?,?,?,?,?,?,?,?,default)
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (NULL,NULL,NULL,NULL,NULL,NULL,'빵빵이',1000,'123',NULL,NULL,NULL,default);
2024-01-29T22:28:07.299+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887299 | took 0ms | rollback | connection 3| url jdbc:h2:mem:~/Marketbridge

;
Hibernate: 
    insert 
    into
        product
        (category_id, created_at, deleted_at, discount_rate, is_own, is_subs, name, price, product_no, stock, thumb_img, updated_at, product_id) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, default)
2024-01-29T22:28:07.309+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887309 | took 0ms | statement | connection 4| url jdbc:h2:mem:~/Marketbridge
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (?,?,?,?,?,?,?,?,?,?,?,?,default)
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (NULL,NULL,NULL,NULL,NULL,NULL,'빵빵이',1000,'123',NULL,NULL,NULL,default);
2024-01-29T22:28:07.317+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887317 | took 0ms | rollback | connection 4| url jdbc:h2:mem:~/Marketbridge

;

java.lang.AssertionError: [Extracted: productId, productNo, name, price, quantity] 
Expecting ArrayList:
  [2L, "123", "빵빵이", 1000L, 2L]
to contain:
  [1L, "123", "빵빵이", 1000L, 2L]
but could not find the following element(s):
  [1L]


	at com.objects.marketbridge.order.service.dto.ProductListResponseDtoTest.ofWithOrderDetail(ProductListResponseDtoTest.java:44)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

 

of 메서드 입니다.

@Getter
public class ProductListResponseDto {

    private Long productId;
    private String productNo;
    private String name;
    private Long price;
    private Long quantity;

    @Builder
    private ProductListResponseDto(Long productId, String productNo, String name, Long price,Long quantity) {
        this.productId = productId;
        this.productNo = productNo;
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }

    public static ProductListResponseDto of(Product product, Long quantity) {
        return ProductListResponseDto.builder()
                .productId(product.getId())
                .productNo(product.getProductNo())
                .name(product.getName())
                .price(product.getPrice())
                .quantity(quantity)
                .build();
    }

    public static ProductListResponseDto of(OrderDetail orderDetail) {
        return ProductListResponseDto.builder()
                .productId(orderDetail.getProduct().getId())
                .productNo(orderDetail.getProduct().getProductNo())
                .name(orderDetail.getProduct().getName())
                .price(orderDetail.getProduct().getPrice())
                .quantity(orderDetail.getQuantity())
                .build();
    }
}

 

현재 Product 엔티티의 Id는 @GeneratedValue(strategy = GenerationType.IDENTITY) 로 이루어져 있습니다.

추가적으로 @ActiveProfiles("test")에 해당하는 yml의 일부는 아래와 같습니다.

datasource:
  url: jdbc:h2:mem:~/Marketbridge
  driver-class-name: org.h2.Driver
  username: sa
  password:

jpa:
  hibernate:
    ddl-auto: none
  show-sql: true
  properties:
    hibernate:
      format_sql: true
      default_batch_fetch_size: 100
  defer-datasource-initialization: true

h2:
  console:
    enabled: true

이런 경우는 처음이라 어디가 잘못됐는지 찾지 못하겠네요 ㅠㅠ

spring mvc jpa querydsl spring-data-mybatis spring-jpa

답변 1

1

y2gcoder

안녕하세요. 유선목님, 공식 서포터즈 y2gcoder입니다.

@GeneratedValue(strategy = GenerationType.IDENTITY)

를 통해 만드는 auto inrement 값은 트랜잭션 롤백의 영향을 받지 않습니다! 아래의 두 링크를 참고해주십쇼!

https://stackoverflow.com/questions/282451/sql-identity-autonumber-is-incremented-even-with-a-transaction-rollback

https://ymkmoon.github.io/Java-29-Jpa-Primary-Key/

 

감사합니다.

1

모깅

감사합니다!

RepositoryTest의 패키지 위치가 domain인 이유

0

29

2

REQUIRES_NEW 해결 방법에 대해서 질문있습니다!!

0

29

1

update()에 사용하는 setter 질문드립니다.

0

47

1

SQL 중심적 개발의 문제점에 대한 질문

0

72

1

혹시 Containing 을 안쓰신 이유가 있을까요?

0

83

2

[공유] 스프링부트 4.x 버전 mybatis 연동

0

173

1

@repository 어노테이션

0

89

3

ItemService

0

58

1

논리 커밋, 물리 커밋 질문드립니다.

0

54

1

내부 트랜잭션 커밋은 필수인가요?

0

57

1

프록시 커넥션 객체를 반환할 때 생성하는건가요?

0

54

1

Transaction readOnly 성능 개선 (김영한님의 대한 감사인사)

2

178

2

JPQL 대신 네이티브 쿼리를 사용해야 하는 경우

0

77

1

@EventListener(ApplicationReadyEvent.class) 관련

0

88

1

트랜잭션 동기화 매니저와 데이터 소스

0

76

1

DB 관련 강의 개설 계획은 없으신건가요?

0

133

2

물리 트랜잭션 과 논리트랜잭션 용어를 맞게 이해한걸까요

0

94

1

스프링 3 버전 이상 rollbackFor 변경된듯요

1

112

1

트랜잭션 전파 질문.

0

87

1

프로젝트 오픈 에러

0

126

1

외부 트랜잭션에서 isNewTransaction이 false로 나오는거에 대해 질문드립니다

0

83

2

같은 스레드를 사용하면 트랜잭션 동기화 매니저는 같은 커넥션을 반환

0

72

1

h2 인메모리 테스트중 예약어 충돌날 경우 대처방법

0

102

1

커스텀aop와 트랜잭션을 같이 사용할때 우선순위에 관한 질문

0

98

2