-
Notifications
You must be signed in to change notification settings - Fork 701
Closed
Labels
status: invalidAn issue that we don't feel is validAn issue that we don't feel is valid
Description
please, help me to figure out.
This is just a simple code.
i'm using spring boot 3.5.7, junit 5, spring r2dbc(mysql)
package test;
import static org.assertj.core.api.Assertions.assertThat;
import io.r2dbc.spi.ConnectionFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.annotation.Id;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.data.relational.core.mapping.Table;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@Log4j2
@SpringBootTest
public class RollbackTest {
@Autowired private R2dbcEntityTemplate template;
@Autowired private TxService txService;
@BeforeEach
void setup() {
template
.getDatabaseClient()
.sql(
"CREATE TABLE IF NOT EXISTS test_item (id SERIAL PRIMARY KEY, name VARCHAR(255), status VARCHAR(50))")
.fetch()
.rowsUpdated()
.block();
template.getDatabaseClient().sql("TRUNCATE TABLE test_item").fetch().rowsUpdated().block();
}
@AfterEach
public void tearDown() {
template
.getDatabaseClient()
.sql("DROP TABLE IF EXISTS test_item")
.fetch()
.rowsUpdated()
.block();
}
@Test
@DisplayName("rollback test")
void testRollbackOnIndividualFailure() {
List<String> items = List.of("Success-1", "FAIL-2", "Success-3", "Success-4");
Flux<TestItem> processingFlux =
Flux.fromIterable(items)
.flatMap(item -> txService.saveInTx(item))
.onErrorContinue((e, item) -> log.error("ERROR CONTINUED: {} for item\n", item, e));
StepVerifier.create(processingFlux).expectNextCount(3).verifyComplete();
long totalCount =
template
.getDatabaseClient()
.sql("SELECT COUNT(*) as count FROM test_item")
.fetch()
.one()
.map(row -> (Long) row.get("count"))
.block();
assertThat(totalCount).isEqualTo(3);
}
@Table("test_item")
record TestItem(@Id Long id, String name, String status) {}
@TestConfiguration(proxyBeanMethods = false)
static class TestConfig {
@Bean
R2dbcEntityTemplate template(ConnectionFactory connectionFactory) {
return new R2dbcEntityTemplate(connectionFactory);
}
@Bean
TxService txService(R2dbcEntityTemplate template) {
return new TxService(template);
}
}
@RequiredArgsConstructor
static class TxService {
private final R2dbcEntityTemplate template;
@Transactional
public Mono<TestItem> saveInTx(String name) {
TestItem item = new TestItem(null, name, "NEW");
Mono<TestItem> saveMono = template.insert(TestItem.class).using(item);
if (name.contains("FAIL")) {
return saveMono.then(Mono.error(new RuntimeException("Simulated TX Failure")));
}
return saveMono;
}
}
}Metadata
Metadata
Assignees
Labels
status: invalidAn issue that we don't feel is validAn issue that we don't feel is valid