Я пытаюсь реализовать транзакции в моем весеннем проекте. С кодом ниже все отлично работает:
@Transactional(rollbackFor=InvocationTargetException.class, propagation =
Propagation.REQUIRED)
public Fraud saveSingleFraud(Fraud fraud, ApplicationPrivateHeader header)
{
@Autowired
private FraudRepository fraudRepo;
@Autowired
private FraudTieRepository fraudTieRepo;
// first insert
fraudRepo.save(fraud);
FraudTie fraudTie = new FraudTie();
fraudTie.setId("6666-6666-6666");
fraudTie.setDbPartKey("0112");
fraudTie.setType("P");
fraudTie.setFraudId("00ed644e-6666-b371");
// second insert (different repo)
fraudTieRepo.save(fraudTie);
}
Но моя реализация не так крута. Мне нужно сделать транзакционную работу с:
Класс контроллера
@RestController
public class FraudController {
@Autowired
private FraudService fraudService;
@PostMapping("testInsertfraud")
public Fraud saveFraudTie( @RequestAttribute(name = HeaderFactory.HEADER_REQUEST_ATTRIBUTE) final ApplicationPrivateHeader header,
@RequestParam(name="dbPartKey", required = true) @Min(4) @Max(4) final String dbPartKey,
@RequestParam(name="trxId", required = true) @Min(36) @Max(36) final String trxId,
@RequestParam(name="jobId", required = false) @Min(36) @Max(36) final String jobId,
@RequestParam(name="jobDbpartKey", required = false) @Min(4) @Max(4) final String jobDbpartKey,
@RequestParam(name="dossierId", required = false) @Min(36) @Max(36) final String dossierId,
@RequestParam(name="dossierDbPartKey", required = false) @Min(4) @Max(4) final String dossierDbPartKey,
@RequestParam(name="certainty", required = true) @Min(1) @Max(1) final String certainty,
@RequestParam(name="isActive", required = true) @Min(1) @Max(1) final int isActive){
Fraud fraud = new Fraud();
fraud.setDbPartKey(dbPartKey);
fraud.setTrxId(trxId);
fraud.setJobId(jobId);
fraud.setJobDbpartKey(jobDbpartKey);
fraud.setDossierId(dossierId);
fraud.setDossierDbPartKey(dossierDbPartKey);
fraud.setCertainty(certainty);
fraud.setIsActive(isActive);
fraud.setCreationTimestamp(AuthParser.getCalendar(System.currentTimeMillis()));
fraud.setEditTimestamp(AuthParser.getCalendar(System.currentTimeMillis()));
fraud.setCreationApplication(header.getAppName());
fraud.setEditApplication(header.getAppName());
fraud.setCreationUserId(header.getUserID());
fraud.setEditUserId(header.getUserID());
return fraudService.saveSingleFraud(fraud, header);
}
}
Класс обслуживания
@Service
public class FraudService {
@Autowired
ActionRetriever retriever;
@Autowired
private FraudRepository fraudRepo;
private Action<SingleEntityContext<Fraud, String>, Fraud> actionSaveFraud;
private Elaboration<SingleEntityContext<Fraud, String>, Fraud> saveElaborationFraud;
@PostConstruct
void init() {
actionSaveFraud = retriever.getActionBean("crud/saveEntity");
saveElaborationFraud = new Elaboration<>(this.actionSaveFraud);
}
@Transactional(rollbackFor=Exception.class, propagation = Propagation.REQUIRED)
public Fraud saveSingleFraud(Fraud fraud, ApplicationPrivateHeader header){
// first insert
Fraud fraude = saveElaborationFraud.execute(new SingleEntityContext<>(header, fraudRepo, fraud));
FraudTie fraudTie = new FraudTie();
fraudTie.setId("6666-6666-6666-6666-9999");
fraudTie.setDbPartKey("0112");
fraudTie.setType("P");
fraudTie.setFraudId("00ed644e-6666-48fa-b371-d53dfbb4ad8c");
// second insert
fraudTie = fraudTieRepo.save(fraudTie);
}
}
Класс разработки
@RequiredArgsConstructor
public class Elaboration<C extends BaseContext, T> {
@NonNull
private final Action<? super C, T> action;
private final List<AdditionalAction<? super C, ? super T>> additionalActions = new ArrayList<>();
public final void addAction(final AdditionalAction<? super C, ? super T> action) {
this.additionalActions.add(action);
}
public T execute(final C context) throws ServiceInvocationException {
final ServiceParameter<? super C> contextParameter = new ServiceParameter<>(context);
final ServiceParameter<T> response = this.action.apply(contextParameter);
final List<ServiceParameter<Void>> additionalResults = new ArrayList<>();
for (final AdditionalAction<? super C, ? super T> additionalAction : this.additionalActions) {
additionalResults.add(additionalAction.apply(contextParameter, response));
}
for (final ServiceParameter<Void> serviceParameter : additionalResults) {
try {
serviceParameter.get();
} catch (final ServiceInvocationException e) {
// This is OK and already logged, going to next action
}
}
return response.get();
}
}
Класс SingleEntityContext
@Getter
public class SingleEntityContext<T, K extends Serializable> extends RepoContext<T, K> {
private T entity;
public SingleEntityContext(String id, String user, String appName, CrudRepository<T, K> repo, T entity) {
super(id, user, appName, repo);
this.entity = entity;
}
public SingleEntityContext(ApplicationPrivateHeader header, CrudRepository<T, K> repo, T entity) {
super(header, repo);
this.entity = entity;
}
public SingleEntityContext(BaseContext ctx, CrudRepository<T, K> repo, T entity) {
super(ctx, repo);
this.entity = entity;
}
}
Класс действий
@Configuration
public class CrudActionFactory {
@Bean("crud/saveEntity")
public <T, K extends Serializable> Action<SingleEntityContext<T, K>, T> saveEntity() throws ServiceInstantiationException{
return ActionsFactory.standard(this.eventPublisher, "crud/saveEntity", context -> context.getRepo().save(context.getEntity()));
}
}
Теперь, с или без @Transaction Fraud и FraudTie сохраняются, но не в транзакции, поэтому при выполнении второго запроса первый запрос уже зафиксирован.
Я пробовал также: (то же самое, запросы работают, но не в транзакции)
@Transactional(rollbackFor=InvocationTargetException.class, propagation = Propagation.REQUIRED)
public Fraud saveSingleFraud(Fraud fraud, ApplicationPrivateHeader header) throws ServiceInvocationException{
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
return (Fraud) transactionTemplate.execute(new TransactionCallback() {
public Fraud doInTransaction(TransactionStatus status) {
Fraud fraude = saveElaborationFraud.execute(new SingleEntityContext<>(header, fraudRepo, fraud));
System.out.println(fraude.getId());
FraudTie fraudTie = new FraudTie();
fraudTie.setId("6666-6666-6666");
fraudTie.setDbPartKey("0112");
fraudTie.setType("P");
fraudTie.setFraudId("00ed644e-6666-b371");
fraudTie = fraudTieRepo.save(fraudTie);
return fraude;
}
});
}
здесь консольный журнал:
2019-06-07 09:41:23,186 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:193 ) - Bound value [org.springframework.orm.jpa.EntityManagerHolder@47a4166a] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] to thread [http-nio-8080-exec-10]
2019-06-07 09:41:23,244 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:140 ) - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@47a4166a] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] bound to thread [http-nio-8080-exec-10]
2019-06-07 09:41:23,253 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:193 ) - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@5f33c1ab] for key [HikariDataSource (HikariPool-1)] to thread [http-nio-8080-exec-10]
2019-06-07 09:41:23,254 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:272 ) - Initializing transaction synchronization
2019-06-07 09:41:23,268 TRACE [http-nio-8080-exec-10 ] (ringframework.transaction.interceptor.TransactionInterceptor:488 ) - Getting transaction for [it.mercury.ws.frame.common.request.FraudService.saveSingleFraud]
2019-06-07 09:41:24,819 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:140 ) - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@47a4166a] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] bound to thread [http-nio-8080-exec-10]
2019-06-07 09:41:24,821 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:140 ) - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@5f33c1ab] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-8080-exec-10]
2019-06-07 09:41:24,852 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:193 ) - Bound value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@d8cf012] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] to thread [pool-27-thread-1]
2019-06-07 09:41:24,920 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:193 ) - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@3bfc38cb] for key [HikariDataSource (HikariPool-1)] to thread [pool-27-thread-1]
2019-06-07 09:41:24,920 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:193 ) - Bound value [org.springframework.orm.jpa.EntityManagerHolder@2c952477] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] to thread [pool-27-thread-1]
2019-06-07 09:41:24,920 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:272 ) - Initializing transaction synchronization
2019-06-07 09:41:24,922 TRACE [pool-27-thread-1 ] (ringframework.transaction.interceptor.TransactionInterceptor:488 ) - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2019-06-07 09:41:24,984 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:140 ) - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@2c952477] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] bound to thread [pool-27-thread-1]
Hibernate:
select
fraud0_.dbPartKey as dbPartKe1_5_0_,
fraud0_.id as id2_5_0_,
fraud0_.certainty as certaint3_5_0_,
fraud0_.creationApplication as creation4_5_0_,
fraud0_.creationTimestamp as creation5_5_0_,
fraud0_.creationUserId as creation6_5_0_,
fraud0_.dossierDbPartKey as dossierD7_5_0_,
fraud0_.dossierId as dossierI8_5_0_,
fraud0_.editApplication as editAppl9_5_0_,
fraud0_.editTimestamp as editTim10_5_0_,
fraud0_.editUserId as editUse11_5_0_,
fraud0_.isActive as isActiv12_5_0_,
fraud0_.jobDbpartKey as jobDbpa13_5_0_,
fraud0_.jobId as jobId14_5_0_,
fraud0_.trxId as trxId15_5_0_
from
Fraud fraud0_
where
fraud0_.dbPartKey=?
and fraud0_.id=?
2019-06-07 09:41:25,153 TRACE [pool-27-thread-1 ] (ringframework.transaction.interceptor.TransactionInterceptor:516 ) - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
Hibernate:
insert
into
Fraud
(certainty, creationApplication, creationTimestamp, creationUserId, dossierDbPartKey, dossierId, editApplication, editTimestamp, editUserId, isActive, jobDbpartKey, jobId, trxId, dbPartKey, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2019-06-07 09:41:25,230 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:331 ) - Clearing transaction synchronization
2019-06-07 09:41:25,231 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:243 ) - Removed value [org.springframework.orm.jpa.EntityManagerHolder@2c952477] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] from thread [pool-27-thread-1]
2019-06-07 09:41:25,231 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:243 ) - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@3bfc38cb] for key [HikariDataSource (HikariPool-1)] from thread [pool-27-thread-1]
2019-06-07 09:41:25,232 TRACE [pool-27-thread-1 ] (mework.transaction.support.TransactionSynchronizationManager:243 ) - Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@d8cf012] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] from thread [pool-27-thread-1]
20470f46-67da-ba25
2019-06-07 09:41:25,239 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:193 ) - Bound value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@d8cf012] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] to thread [http-nio-8080-exec-10]
2019-06-07 09:41:25,240 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:140 ) - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@47a4166a] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] bound to thread [http-nio-8080-exec-10]
2019-06-07 09:41:25,240 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:140 ) - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@5f33c1ab] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-8080-exec-10]
2019-06-07 09:41:25,241 TRACE [http-nio-8080-exec-10 ] (ringframework.transaction.interceptor.TransactionInterceptor:488 ) - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2019-06-07 09:41:25,247 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:140 ) - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@47a4166a] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] bound to thread [http-nio-8080-exec-10]
Hibernate:
select
fraudtie0_.dbPartKey as dbPartKe1_6_0_,
fraudtie0_.id as id2_6_0_,
fraudtie0_.fraudId as fraudId3_6_0_,
fraudtie0_.type as type4_6_0_
from
FraudTie fraudtie0_
where
fraudtie0_.dbPartKey=?
and fraudtie0_.id=?
2019-06-07 09:41:25,253 TRACE [http-nio-8080-exec-10 ] (ringframework.transaction.interceptor.TransactionInterceptor:516 ) - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2019-06-07 09:41:25,253 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:243 ) - Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@d8cf012] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] from thread [http-nio-8080-exec-10]
2019-06-07 09:41:25,254 TRACE [http-nio-8080-exec-10 ] (ringframework.transaction.interceptor.TransactionInterceptor:516 ) - Completing transaction for [it.mercury.ws.frame.common.request.FraudService.saveSingleFraud]
Hibernate:
insert
into
FraudTie
(fraudId, type, dbPartKey, id)
values
(?, ?, ?, ?)
2019-06-07 09:41:25,264 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:331 ) - Clearing transaction synchronization
2019-06-07 09:41:25,265 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:243 ) - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@5f33c1ab] for key [HikariDataSource (HikariPool-1)] from thread [http-nio-8080-exec-10]
2019-06-07 09:41:25,424 TRACE [http-nio-8080-exec-10 ] (mework.transaction.support.TransactionSynchronizationManager:243 ) - Removed value [org.springframework.orm.jpa.EntityManagerHolder@47a4166a] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@e3ba1c5] from thread [http-nio-8080-exec-10]
Я полагаю, что проблема связана с Generics, пожалуйста, помогите мне найти решение.