晚安,伙計們。
我有一個從端點呼叫的方法,該方法將物件保存在我的資料庫中,并且我想通過在服務內部發生任何例外的情況下回滾事務來為該代碼添加一些“保護”。
我使用 JAX-RS 作為 REST API 部分,使用 OracleDB 作為資料庫。我的代碼如下。
端點:
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response createAcordo(AcordoDTO acordoDTO) {
return acordosService.save(acordoDTO, token);
}
服務:
@Transactional(rollbackOn = Exception.class)
public Response save(AcordoDTO acordoDTO, String token) {
try {
... some bisiness logic and validation
Acordo acordo = acordoRepository.save(AcordoConverter.toAcordo(acordoDTO));
UserDTO usr = getUserInfoFromToken();
ApprovalDTO approvalDTO = new ApprovalDTO ();
approvalDTO .setUser(usr.getName()); // this method is throwing null pointer exception
// because usr is null
return Response.status(Response.Status.CREATED).entity(acordo).build();
} catch (Exception e) {
return new SystemErrorException().toResponse();
}
}
盡管有例外和@Transactional 注釋,上面的代碼仍將新Acordo物件保存到資料庫中。然而,我期望發生的是整個事務被回滾并且沒有物件被保存。總之,我想知道的是:
- 我誤解了有關 @Transactional 使用的任何概念?
- 如何修復此代碼以實作預期目標(回滾)?
PS.1 - 我試過沒有try/catch阻塞,結果是一樣的。save() 仍然將物件提交到資料庫。
PS.2 - acordoRepository.save() 有 @Transaction 注釋。
PS.3 - 我嘗試TransactionSynchronizationRegistry.setRollbackOnly()在 catch 塊內添加它并且它有效。然而(對我來說)它看起來更像是一個騙子而不是一個正確的解決方案。
PS.4 - 在我使用TransactionSynchronizationRegistry.setRollbackOnly()交易狀態之后STATUS_MARKED_ROLLBACK,在所有其他測驗中都是STATUS_ACTIVE。
更新 1
我acordoRepository.save()的如下。我試圖檢查是否有一個或兩個交易。為了做到這一點,我嘗試(不確定這是一個好主意)tsr.getTransactionKey()在我的Service.save()and上列印兩者acordoRepository.save(),結果是相同的 key,這讓我相信只有一筆交易。
@Resource
TransactionSynchronizationRegistry tsr; // I injected it here
// for testing purposes
@Transactional
public T save(T entity) {
if (entity.getId() == null) {
entityManager.persist(entity);
} else {
entityManager.merge(entity);
}
entityManager.flush();
return find(entity.getId());
}
更新2:
我persistence.xml的如下。
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="namePU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>java:/nameDS</non-jta-data-source>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<jar-file>lib/client-notification-1.30.jar</jar-file>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
<property name="hibernate.connection.autocommit" value="false"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.generate_statistics" value="false"/>
<!-- desabilita JSR-303 no save/update -->
<property name="javax.persistence.validation.mode" value="none"/>
</properties>
</persistence-unit>
</persistence>
最好的問候,
托馬斯。
uj5u.com熱心網友回復:
如果您希望該@Transactional方法回滾,則不得在該方法中捕獲例外。洗掉catch(Exception)fromsave并在 createAcordo 中捕獲它。那應該行得通。
uj5u.com熱心網友回復:
可能你可以嘗試使用 Throwable.class 而不是 Exception.class 因為 throwable 是 if 的超類,如果洗掉 try/catch 順便說一下默認情況下 spring 會處理 rollBack 但即使我們明確宣告,它也會檢查選中/未選中特別是例外 - rollbackFor = {AnyException.class} 用于檢查例外,因為 runtimeException 將由 spring 本身處理,您可以查看以下示例:https ://www.netsurfingzone.com/spring/transactional-rollbackfor-example-using-spring-boot /
uj5u.com熱心網友回復:
在我無法對代碼發表評論之后:)我正在回答:我認為你可以使用這樣的例外:
@Transactional(rollbackOn = CustomeException.class)
public Response save(AcordoDTO acordoDTO, String token) {
try {
... some bisiness logic and validation
if(! valid)
throw new CustomeException();
Acordo acordo = acordoRepository.save(AcordoConverter.toAcordo(acordoDTO));
UserDTO usr = getUserInfoFromToken();
ApprovalDTO approvalDTO = new ApprovalDTO ();
approvalDTO .setUser(usr.getName()); // this method is throwing null pointer exception
// because usr is null
// if this code throws any exception then throw runtime exception in your catch bloke
return Response.status(Response.Status.CREATED).entity(acordo).build();
} catch (Exception e) {
throw new CustomeException();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/479949.html
