我開發了一個測驗專案來重現這個問題。
這是一個專案結構:

pom.xml 檔案:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>value-updated-after-fail-spring</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>
Persone.java 檔案:
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@RequiredArgsConstructor
@AllArgsConstructor
@Builder
@Getter
@Setter
@ToString
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Column(nullable = false)
@NonNull
String name;
}
PersonRepository.java 檔案:
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {}
PersonService.java 檔案:
@Component
public class PersonService {
private final PersonRepository repository;
public PersonService(PersonRepository repository) {
this.repository = repository;
}
@Transactional
public Person create(String name) {
return repository.save(new Person(name));
}
@Transactional
public Person save(Person person) {
if(StringUtils.isBlank(person.getName())) {
throw new RuntimeException();
}
Person personFromDB = getById(person.getId());
personFromDB.setName(person.getName());
return repository.save(personFromDB);
}
@Transactional
public Person getById(Long id) {
return repository.findById(id)
.orElseThrow(NullPointerException::new);
}
@Transactional
public void deleteAll() {
repository.deleteAll();
}
}
application.properties 檔案:
spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.h2.console.enabled=true
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
TestApplicationConfiguration.java 檔案
@SpringBootConfiguration
@EnableAutoConfiguration
@EnableJpaRepositories
@EntityScan("net.example.model")
@ComponentScan(basePackages = "net.example")
public class TestApplicationConfiguration {}
PersonServiceTest.java 檔案:
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class PersonServiceTest {
@Autowired
private PersonService service;
@AfterEach
void tearDownEach() {
service.deleteAll();
}
@Test
void rename() {
String expected = "name";
Person person = service.create(expected);
Person personFromDB = service.getById(person.getId());
personFromDB.setName("");
assertThrows(RuntimeException.class, () -> service.save(personFromDB));
assertEquals(expected, service.getById(personFromDB.getId()).getName());
}
}
問題:最后一個斷言失敗
org.opentest4j.AssertionFailedError:
Expected :name
Actual :
我已經嘗試解決這個問題了嗎?
- 我試圖洗掉
@TransactionalPersonService#getById 方法的注釋以避免從快取中獲取物體。- 這并沒有解決問題 - 我試圖添加
spring.cache.type=none到application.properties檔案以禁用快取。- 這并沒有解決問題
為什么我認為它是快取?
當我對此進行除錯時,我發現該PersonService#getById()方法沒有回傳實際資料,但該方法回傳了一個標題已更改的快取物件。呼叫該PersonService#save方法后資料庫未更改,因為它引發了例外

也許我沒有正確開發測驗。也許我應該改變保存更改資料的方法。
請分享最佳實踐和文章,以更好地了解如何更新資料以及如何正確配置和撰寫 Spring Boot 應用程式的測驗。
uj5u.com熱心網友回復:
非常感謝
在第一個螢屏截圖中,您可以看到注釋SpringExtension中定義的 ,在@DataJpaTest呼叫每個測驗之前打開一個新會話。

在第二個螢屏截圖中,您可以看到SpringExtension在呼叫每個測驗后關閉會話。
我決定覆寫默認的事務傳播:
@Transactional(propagation = Propagation.NEVER)當方法被呼叫時它不會創建事務,如果在現有事務中呼叫該方法則拋出例外
對我有幫助的鏈接:
- 資料訪問
- Spring @Transactional 中的事務傳播和隔離
- 帶有插圖的交易傳播
- Hibernate 快取 - 一級快取
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/505380.html
上一篇:Postgres序列上的NamedNativeQuery無法確定回傳型別
下一篇:使用SpringJPA保持級聯
