简体   繁体   English

在Spring @Transactional内部启用JPA保存且多个实体不会回滚,并启用了Exception.class的回滚

[英]JPA save with multiple entities not rolling back when inside Spring @Transactional and rollback for Exception.class enabled

I have been at this for a good few hours and I can not find a way to get around what seems to be JPARepository automatically starting/committing a transaction when I save entities inside an encapsulating transaction. 我已经待了好几个小时了,当我将实体保存在封装事务中时,我找不到能自动解决JPARepository自动启动/提交事务的方法。

I create 3 entities in total. 我总共创建了3个实体。 The first 2, ClientAdmin and CreditPot are to be made so when the third Institution entity is made, the entities can form relationships before being persisted. 将创建第一个2, ClientAdminCreditPot ,以便在创建第三个Institution实体时,这些实体可以在持久化之前形成关系。

When an Exception is thrown, I wanted it so that the created entities are NOT COMMITED (ie the entire process rolled back). 当抛出一个异常时,我希望它可以使创建的实体不被提交(即整个过程回滚)。

At the moment, I can see in the logs that the JPA Save method may start its own transaction (I don't fully understand the logs) which causes the entities that have called repo.save(entity) to be committed in their own transaction? 目前,我在日志中看到JPA Save方法可能会启动其自己的事务(我不完全了解日志),这会导致调用repo.save(entity)在其自己的事务中提交?

Any help would be greatly appreciated. 任何帮助将不胜感激。

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void createInstitution(InstitutionSignUpForm form) throws Exception {

    //Create Admin account.
    ClientAdmin clientAdmin = new ClientAdmin();
    clientAdmin.setRole(roleRepo.findOneByRole("SUPER_ADMIN").orElseThrow(() -> new Exception("Can not resolve role SUPER_ADMIN")));
    clientAdmin.setPassword(passwordEncoder.encode(form.getPassword()));
    clientAdmin.setUsername(form.getUsername());
    clientAdmin = clientAdminRepo.save(clientAdmin);

    //Create Credit Pot for institution.
    CreditPot creditPot = new CreditPot();
    creditPot.setIsPrimaryPot(true);
    creditPot.setName("Primary Credit Pot");
    creditPot.setCredits(300L);
    creditPot = creditPotRepo.save(creditPot);

    System.out.println("Throwing Exception.");
    if(1==1) throw new Exception("!!!", new Throwable("!!!"));

    //Create institution and assign relationships.
    Institution institution = new Institution();
    institution.setDiceCode(dicewareGenerator.generateRandomPassword(6));
    institution.setName(form.getInstitutionName());
    institution.setPrimaryCreditPot(creditPot);
    clientAdmin.setInstitution(institution);
    institutionRepo.saveAndFlush(institution);
}

The logs: 日志:

    2019-09-12 10:46:41.148 DEBUG 24621 --- [nio-5000-exec-6] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2019-09-12 10:46:41.148 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.149 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.149 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(652375272<open>)] for JPA transaction
2019-09-12 10:46:41.149 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.j3den.edu.webserver.services.sigup.InstitutionSignUpService.createInstitution]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Exception
2019-09-12 10:46:41.150 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@74972cba]
2019-09-12 10:46:41.150 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder@19e50439] for key [HikariDataSource (HikariPool-1)] to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.150 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2019-09-12 10:46:41.150 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.TransactionInterceptor           : Getting transaction for [com.j3den.edu.webserver.services.sigup.InstitutionSignUpService.createInstitution]
2019-09-12 10:46:41.150 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@304f1d77] for key [public abstract java.util.Optional com.j3den.edu.models.repos.RoleRepo.findOneByRole(java.lang.String)] to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.151 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.TransactionInterceptor           : No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findOneByRole]: This method is not transactional.
2019-09-12 10:46:41.151 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.151 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.153 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@304f1d77] for key [public abstract java.util.Optional com.j3den.edu.models.repos.RoleRepo.findOneByRole(java.lang.String)] from thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.242 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@2d5257a2] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.242 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.242 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(652375272<open>)] for JPA transaction
2019-09-12 10:46:41.242 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@19e50439] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.243 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
2019-09-12 10:46:41.243 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.TransactionInterceptor           : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2019-09-12 10:46:41.243 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.244 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2019-09-12 10:46:41.245 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@2d5257a2] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] from thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.245 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@2d5257a2] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.245 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.245 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(652375272<open>)] for JPA transaction
2019-09-12 10:46:41.245 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@19e50439] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.245 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
2019-09-12 10:46:41.245 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.TransactionInterceptor           : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2019-09-12 10:46:41.245 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] bound to thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.246 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2019-09-12 10:46:41.247 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@2d5257a2] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] from thread [http-nio-5000-exec-6]
Throwing Exception.
2019-09-12 10:46:41.247 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.TransactionInterceptor           : Completing transaction for [com.j3den.edu.webserver.services.sigup.InstitutionSignUpService.createInstitution] after exception: java.lang.Exception: !!!
2019-09-12 10:46:41.247 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.RuleBasedTransactionAttribute    : Applying rules to determine whether transaction should rollback on java.lang.Exception: !!!
2019-09-12 10:46:41.247 TRACE 24621 --- [nio-5000-exec-6] o.s.t.i.RuleBasedTransactionAttribute    : Winning rollback rule is: RollbackRuleAttribute with pattern [java.lang.Exception]
2019-09-12 10:46:41.247 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction rollback
2019-09-12 10:46:41.247 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Rolling back JPA transaction on EntityManager [SessionImpl(652375272<open>)]
2019-09-12 10:46:41.248 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2019-09-12 10:46:41.248 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder@19e50439] for key [HikariDataSource (HikariPool-1)] from thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.248 DEBUG 24621 --- [nio-5000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Not closing pre-bound JPA EntityManager after transaction
2019-09-12 10:46:41.248 TRACE 24621 --- [nio-5000-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder@5ed67928] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@70286b92] from thread [http-nio-5000-exec-6]
2019-09-12 10:46:41.248 DEBUG 24621 --- [nio-5000-exec-6] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor

MySQL historically by default created tables using the MyISAM engine, which didn't support transactions. MySQL历史上默认情况下使用MyISAM引擎创建表,该引擎不支持事务。 Later InnoDB was added which did support transactions, however MyISAM remained the default for quite some time. 后来添加了支持事务的InnoDB,但是MyISAM在相当长的一段时间内仍然是默认值。

Hibernate with its dialects followed the same defaults and hence the default for the MySQL dialect is MyISAM (for backwards compatibility). Hibernate的方言遵循相同的默认值,因此MySQL方言的默认值为MyISAM(为了向后兼容)。

You have 2 ways to fix this, either select a specific dialect or toggle from MyISAM to InnoDB with a specific property. 您可以通过2种方法来解决此问题:选择特定的方言,或使用特定的属性从MyISAM切换到InnoDB。

To select a dialect use the spring.jpa.database-platform to specify the required dependency. 要选择一种方言,请使用spring.jpa.database-platform指定所需的依赖关系。

spring.jpa.database-platform=org.hibernate.dialect.MySQL57InnoDBDialect`

or to set the property use 或设置属性使用

spring.jpa.properties.hibernate.dialect.storage_engine=innodb

or a combination of both (as the MySQL57InnoDBDialect is deprecated now that there is the hibernate.dialect.storage_engine property). 或两者的组合(因为不存在MySQL57InnoDBDialect ,因为现在有了hibernate.dialect.storage_engine属性)。

spring.jpa.database-platform=org.hibernate.dialect.MySQL57Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb

See also: https://in.relation.to/2017/02/20/mysql-dialect-refactoring/ 另请参见: https : //in.relation.to/2017/02/20/mysql-dialect-refactoring/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM