@Transactional을 사용하지 않고 스프링 테스트를 통해 MariaDB 데이터베이스에 대한 변경 롤백
다음과 같은 기능을 제공하는 스프링 서비스가 있습니다.
@Service
public class MyService {
@Transactional(propagation = Propagation.NEVER)
public void doStuff(UUID id) {
// call an external service, via http for example, can be long
// update the database, with a transactionTemplate for example
}
}
전파.NEVER는 외부 서비스로부터의 응답을 기다리는 동안 데이터베이스에 대한 연결을 차단하지 않기 때문에 메서드가 호출될 때 활성 트랜잭션이 없어야 함을 나타냅니다.
이 테스트를 적절하게 수행한 후 데이터베이스를 롤백하려면 어떻게 해야 합니까?@Transactional on Test는 동작하지 않습니다.Propagation으로 인해 예외가 발생합니다.절대.
@SpringBootTest
@Transactional
public class MyServiceTest {
@Autowired
private MyService myService;
public void testDoStuff() {
putMyTestDataInDb();
myService.doStuff(); // <- fails no transaction should be active
assertThat(myData).isTheWayIExpectedItToBe();
}
}
@Transactional을 삭제할 수 있지만 다음 테스트를 위해 데이터베이스가 일관된 상태가 아닙니다.
현시점에서는 각 테스트 후에 @AfterJunit 콜백으로 데이터베이스의 모든 테이블을 잘라내는 것이 해결책입니다만, 데이터베이스에 테이블이 여러 개 있는 경우, 이것은 다소 투박하고 느려집니다.
여기서 질문하겠습니다.어떻게 하면 @Transactional을 잘라내거나 사용하지 않고 데이터베이스에 변경을 롤백할 수 있을까요?
테스트 대상 데이터베이스는 테스트 컨테이너를 사용하는 mariadb이므로 mariadb/mysql에서만 동작하는 솔루션이면 충분합니다.하지만 좀 더 일반적인 것이 좋을 것 같아!
(테스트에서 @Transactional을 사용하지 않고 싶은 또 다른 예: 가끔은 트랜잭션 경계가 코드에 올바르게 삽입되어 있는지 테스트하고 싶기도 합니다.또, 프로덕션 코드에 @Transactional을 잊어버렸기 때문에 런타임에 로딩이 늦어지는 예외가 발생하지 않도록 하고 싶기도 합니다).
도움이 되는 경우, 다른 몇 가지 주의사항이 있습니다.
- 휴지 상태에서의 JPA 사용
- 응용 프로그램 컨텍스트가 시작될 때 데이터베이스가 licibase로 생성됩니다.
내가 가지고 놀았던 다른 아이디어:
- @DirtiesContext: 이것은 매우 느립니다.새로운 콘텍스트를 작성하는 것은 단순히 데이터베이스 내의 모든 테이블을 잘라내는 것보다 훨씬 비용이 많이 듭니다.
- MariaDB SAVEPOINT: 막다른 골목. 트랜잭션 내부 데이터베이스 상태로 되돌리는 방법일 뿐입니다.글로벌하게 작업할 수 있다면 이상적인 솔루션 IMO가 될 것입니다.
- 연결을 만지작거리고 있습니다.
START TRANSACTION
테스트 전 데이터 소스에 대한 설명과ROLLBACK
테스트 후: 매우 더럽고, 작동시킬 수 없었다.
의견: 인인의의 personal:@Transactional
+@SpringBootTest
는 (에서는) (안티패턴)과 spring.jpa.open-in-view
네, 처음에는 쉽게 작업을 할 수 있고 자동 롤백이 되는 것은 좋지만 트랜잭션에 대한 유연성과 제어력이 크게 상실됩니다.수동 트랜잭션 관리가 필요한 모든 것을 테스트하는 것은 매우 어려워집니다.
가 있었고, 결국 꾹 참고 꾹 참기로 했다.@DirtiesContext
이 더 는 실제 트랜잭션 가 발견될 이 높아집니다.네, 테스트를 실행하는 데 30분이 더 걸리지만 테스트된 서비스는 실제 가동과 동일하게 동작하며 테스트에서 트랜잭션 문제가 발견될 가능성이 높습니다.
다만, 전환하기 전에, 다음의 회피책의 사용을 검토했습니다.
- 다음과 같은 인터페이스와 서비스를 만듭니다.
interface TransactionService
{
void runWithoutTransaction(Runnable runnable);
}
@Service
public class RealTransactionService implements TransactionService
{
@Transactional(propagation = Propagation.NEVER)
public void runWithoutTransaction(Runnable runnable)
{
runnable.run();
}
}
- 이 "http"로 되어 .
#runWithoutTransaction
- - 법, 예):
@Service
public class MyService
{
@Autowired
private TransactionService transactionService;
public void doStuff(UUID id)
{
transactionService.runWithoutTransaction(() -> {
// call an external service
})
}
}
제품 가 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」Propagation.NEVER
해 주세요는, 「」를 할 수 있습니다.TransactionService
다른 실장 기능을 탑재하고 있습니다.@Transactional
★★★★★★★★★★★★★★★★:
@Service
@Primary
public class FakeTransactionService implements TransactionService
{
// No annotation here
public void runWithoutTransaction(Runnable runnable)
{
runnable.run();
}
}
은 비단 에만 이 아니다.Propagation.NEVER
다른 전파 타입도 같은 방법으로 실장할 수 있습니다.
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void runWithNewTransaction(Runnable runnable)
{
runnable.run();
}
- ★★★★★★★★★★★★★★★★★★★★★★★★★★★.Runnable
는 a로 대체할 수 .Function
/Consumer
/Supplier
메서드가 값을 반환 및/또는 수용해야 하는 경우.
좀 엉뚱한 생각이지만, mysql 데이터베이스를 사용하고 있다면 테스트를 위해 dolt로 전환해도 될까요?
Dolt는 Git 저장소처럼 Fork, Clone, Branch, Marge, Push, Pull이 가능한 SQL 데이터베이스입니다.
테스트 컨테이너 컨테이너로 포장하고, 시작 시 필요한 데이터를 로드한 다음 각 테스트 실행 돌트 재설정 시작 시 필요한 데이터를 로드할 수 있습니다.
언급URL : https://stackoverflow.com/questions/72534889/rollback-changes-done-to-a-mariadb-database-by-a-spring-test-without-transactio
'programing' 카테고리의 다른 글
PHP: __('Some text')의 역할은 무엇입니까? (0) | 2022.12.13 |
---|---|
최대 연결 끊김 (0) | 2022.12.13 |
Python 목록의 값을 사용하여 .csv 파일을 만듭니다. (0) | 2022.12.03 |
두 타임스탬프 간의 MySql 차이(일) (0) | 2022.12.03 |
persistence.xml에 요소가 필요합니까? (0) | 2022.12.03 |