Почему @Transactional не работает с Generics - PullRequest
0 голосов
/ 07 июня 2019

Я пытаюсь реализовать транзакции в моем весеннем проекте. С кодом ниже все отлично работает:

@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, пожалуйста, помогите мне найти решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...