當內部方法分別是事務性的時,我想在服務層中測驗一個非事務性方法。我想知道如果某些方法拋出例外會發生什么。它是否正確回滾?我也嘗試過rollbackFor,但沒有幫助。有什么建議?
- 春天 v-2.5.1
應用程式屬性
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=create-drop
server.error.include-message=always
server.error.include-binding-errors=always
控制器
@PostMapping("/test")
public void test(){
service.test();
}
服務
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
public void test() {
User user1 = new User();
String encodedPassword = passwordEncoder.encode("123");
user1.setUsername("username");
user1.setPassword(encodedPassword);
user1.setFirst_name("name1");
user1.setLast_name("family1");
save(user1);
User update = update(user1.getUsername());
throw new RuntimeException();// I expect Spring rollback all data for save and update methods
//but it seems data has been committed before an exception occur.
}
@Transactional
public void save(User user) {
if (userExists(user.getUsername()))
throw new ApiRequestException("Username has already taken!");
else {
User user1 = new User();
String encodedPassword = passwordEncoder.encode(user.getPassword());
user1.setUsername(user.getUsername());
user1.setPassword(encodedPassword);
user1.setFirst_name(user.getFirst_name());
user1.setLast_name(user.getLast_name());
user1.setCreate_date(user.getCreate_date());
user1.setModified_date(user.getModified_date());
user1.setCompany(user.getCompany());
user1.setAddresses(user.getAddresses());
userRepository.save(user1);
// throw new RuntimeException(); Similarly I expect rollback here.
}
}
@Transactional
public User update(String username) {
User userFromDb = userRepository.findByUsername(username);
userFromDb.setFirst_name("new username");
userFromDb.setLast_name("new lastname");
return userRepository.save(userFromDb);
}
}
uj5u.com熱心網友回復:
由于默認情況下spring代理的作業方式,您不能從實體中呼叫“代理”方法。
考慮一下,當您@Transactional在方法上添加注釋時,Spring 會為該類創建一個代理,并且該代理是處理事務開始/提交/回滾的地方。代理呼叫實際的類實體。春天對你隱藏了這一點。
但是鑒于此,如果您在類實體 ( test()) 上有一個方法,該方法在其自身 () 上呼叫另一個方法this.save(),則該呼叫不會通過代理,因此沒有“@Transactional”代理。發生 RuntimeException 時,無需進行任何回滾。
有一些方法可以改變 Spring 的代理方式,這將允許它作業,但多年來它已經發生了變化。有多種選擇。一種方法是創建單獨的類。也許是 UserServiceHelper。UserServiceHelper 包含由 UserService 呼叫的 @Transactional 方法。當需要不同的@Transactional 隔離和傳播時,也會出現同樣的問題。
相關答案和資訊:
- Spring @Transaction 方法被同一個類內的方法呼叫,不起作用?
- Spring @Transactional 屬性是否適用于私有方法?
- Spring事務不回滾
您的示例代碼對于您要執行的操作不是很清楚。通常,@Transactional將放在服務類上并應用于所有公共方法(如test())。
uj5u.com熱心網友回復:
首先,我不確定您是否了解交易的含義。如果有一個包含多個要執行的功能的作業單元,并且您希望它們完全失敗或完全通過 - 這就是您使用事務的時候。
那么在test()方法的情況下 - 為什么底層機制(在這種情況下是 Hibernate)應該關心回滾發生在內部的事情save()以及update()當它test()本身不是事務時?
很抱歉問的不僅僅是回答,但據我所知 - 您需要使用注釋test()進行注釋,而不是單個方法。或者您可以對它們全部進行注釋。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/450495.html
上一篇:無法決議mojoorg.springframework.boot:spring-boot-maven-plugin的配置
下一篇:不想將DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD與TestContainers一起使用
