我正在玩 Spring 和@Transactional注釋。我正在做一個簡單的實驗來測驗這個注釋的行為。這些是我的超級簡單的java類:
我的域名:
package com.xxx.springdemo.transactionalAnnotation.domain;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
@Data
@Entity
public class Counter {
@Id
int id;
int count = 0;
}
我的服務:
package com.xxx.springdemo.transactionalAnnotation.services;
import com.xxx.springdemo.transactionalAnnotation.domain.Counter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class TransactionalService {
public void throwException(Counter counter) {
counter.setCount(1);
throw new RuntimeException("Runtime exception");
}
public void dontThrowException(Counter counter) {
counter.setCount(2);
}
}
和我的控制器:
package com.xxx.springdemo.transactionalAnnotation.controllers;
import com.xxx.springdemo.transactionalAnnotation.domain.Counter;
import com.xxx.springdemo.transactionalAnnotation.services.TransactionalService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class TransactionController {
private final TransactionalService transactionalService;
@GetMapping("test-transactional")
public void testTransactional() {
Counter counter = new Counter();
try {
transactionalService.throwException(counter);
} catch (Exception e) {
System.out.println("Exception caught: " e.getMessage());
}
System.out.println("Variable hasn't changed (counter = " counter.getCount() ")");
}
@GetMapping("test-transactional-2")
public void testTransactionalWithoutException() {
Counter counter = new Counter();
try {
transactionalService.dontThrowException(counter);
} catch (Exception e) {
System.out.println("Exception caught: " e.getMessage());
}
System.out.println("Variable changed (counter = " counter.getCount() ")");
}
}
代碼應該是不言自明的。我希望列印:
變數沒有改變(計數器 = 0)
如果test-transactional端點被呼叫。我得到的是:
變數沒有改變(計數器 = 1)
這意味著在服務方法throwException中,count 屬性在拋出例外后不會回滾。
PS 這是我的 build.gradle 檔案:
plugins {
id 'org.springframework.boot' version '2.6.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
uj5u.com熱心網友回復:
Spring@Transactional只是一種管理底層 JPA 事務的宣告方式。所以它取決于規范定義的 JPA 的回滾行為。如下 :
對于事務范圍的持久性背景關系和連接到當前事務的擴展持久性背景關系,事務回滾會導致所有預先存在的托管實體和已洗掉的實體[29] 分離。實體的狀態將是事務回滾時實體的狀態。事務回滾通常會導致持久性背景關系在回滾時處于不一致的狀態。
Hibernate檔案也提到了相同的內容:
回滾資料庫事務不會使您的業務物件回到事務開始時的狀態。這意味著資料庫狀態和業務物件將不同步。通常,這不是問題,因為例外是不可恢復的,無論如何您都必須在回滾后重新開始。
Counter因此,在事務回滾之前(即)仍將具有狀態,這是預期的回滾行為count=1。
對于已經存在于 DB 中的物體,您可以手動將其狀態恢復到與 DB 相同的狀態,方法是使用entityManager.refresh()或簡單地使用entityManager.get()JPQL 從 DB 中再次檢索它。
對于資料庫中不存在的物體,只需重新執行代碼重新創建即可。
所以這里的回滾只是意味著資料庫中不會更新任何內容。這并不意味著它將物件狀態恢復到執行@Transactional方法之前的那一刻。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/424540.html
