防止内部事务回滚外部事务

时间:2014-05-28 06:36:10

标签: java hibernate transactions spring-data

我有一个有点复杂的交易,它会创建或不创建许多不同类型的实体。如果由于验证错误而无法创建其中一个实体,我想简单地捕获ConstraintValidationError并继续(允许在同一事务中创建的任何其他实体成功保存)。

我可以成功完成此操作,但验证错误仍然标记了我的整个回滚事务,这是我不想要的。

我尝试更改单个验证方法,该方法导致ConstraintValidationError具有:

@Transactional(propagation = Propagation.NOT_SUPPORTED)

强制一个新的事务,认为它只会标记用于回滚的新的内部事务,但似乎并非如此。

调用类标有:

@Transactional(noRollbackFor=ConstraintViolationException.class)

但是如果ConstraintViolationException在被调用的方法中并且我不希望将它添加到被调用的方法中,这没有用。

做这样的事情的正确方法是什么?

(如果需要代码,请告诉我 - 示例有点复杂。)

编辑(2014年5月26日):

当我尝试

progration = Propagation.REQUIRES_NEW

我看到结果没有变化。此特定日志来自有意尝试使用空描述保存“部门”实体对象的测试,该描述无效:

11:46:43.599 [main] DEBUG org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'DefaultCourseManager.saveDepartment' with attribute: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT; ''
11:46:43.599 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
11:46:43.599 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Found thread-bound EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3a90c13c] for JPA transaction
11:46:43.599 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Suspending current transaction, creating new transaction with name [edu.ucdavis.dss.dw.site.DefaultCourseManager.saveDepartment]
11:46:43.600 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@67b355c8] for JPA transaction
11:46:43.600 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl - begin
11:46:43.600 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Obtaining JDBC connection
11:46:43.601 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Obtained JDBC connection
11:46:43.601 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - initial autocommit status: true
11:46:43.601 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - disabling autocommit
11:46:43.601 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@388623ad]
11:46:43.601 [main] DEBUG org.springframework.data.repository.core.support.TransactionalRepositoryProxyPostProcessor$CustomAnnotationTransactionAttributeSource - Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
11:46:43.602 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
11:46:43.602 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Found thread-bound EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@67b355c8] for JPA transaction
11:46:43.602 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Participating in existing transaction
11:46:43.606 [main] DEBUG org.hibernate.SQL - select KeyValue from SurrogateKeys where TableName = 'Departments' for update
11:46:43.608 [main] DEBUG org.hibernate.SQL - insert into SurrogateKeys(TableName, KeyValue) values('Departments', ?)
11:46:43.610 [main] DEBUG org.hibernate.SQL - update SurrogateKeys set KeyValue = ? where KeyValue = ? and TableName = 'Departments'
11:46:43.612 [main] DEBUG org.hibernate.SQL - select KeyValue from SurrogateKeys where TableName = 'Departments' for update
11:46:43.612 [main] DEBUG org.hibernate.SQL - update SurrogateKeys set KeyValue = ? where KeyValue = ? and TableName = 'Departments'
11:46:43.613 [main] DEBUG org.hibernate.event.internal.AbstractSaveEventListener - Generated identifier: 1, using strategy: org.hibernate.id.MultipleHiLoPerTableGenerator
11:46:43.613 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction commit
11:46:43.613 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@67b355c8]
11:46:43.613 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl - committing
11:46:43.613 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Processing flush-time cascades
11:46:43.614 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Dirty checking collections
11:46:43.614 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 1 insertions, 0 updates, 0 deletions to 1 objects
11:46:43.614 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
11:46:43.614 [main] DEBUG org.hibernate.internal.util.EntityPrinter - Listing entities:
11:46:43.614 [main] DEBUG org.hibernate.internal.util.EntityPrinter - edu.ucdavis.dss.dw.entities.Department{courses=null, code=null, name=null, id=1}
11:46:43.620 [main] DEBUG org.hibernate.validator.resourceloading.PlatformResourceBundleLocator - ValidationMessages not found.
11:46:43.624 [main] DEBUG org.hibernate.validator.resourceloading.PlatformResourceBundleLocator - org.hibernate.validator.ValidationMessages found.
11:46:43.637 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl - rolling back
11:46:43.638 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - rolled JDBC Connection
11:46:43.638 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - re-enabling autocommit
11:46:43.639 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@67b355c8] after transaction
11:46:43.640 [main] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
11:46:43.648 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Releasing JDBC connection
11:46:43.649 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Released JDBC connection
11:46:43.649 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Resuming suspended transaction after completion of inner transaction
11:46:43.651 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction rollback
11:46:43.651 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Rolling back JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3a90c13c]
11:46:43.651 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl - rolling back
11:46:43.651 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - rolled JDBC Connection
11:46:43.651 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - re-enabling autocommit
11:46:43.652 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@3a90c13c] after transaction
11:46:43.652 [main] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
11:46:43.652 [main] DEBUG org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl - HHH000420: Closing un-released batch
11:46:43.652 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Releasing JDBC connection
11:46:43.653 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Released JDBC connection
11:46:43.655 [main] DEBUG com.github.springtestdbunit.DbUnitTestExecutionListener - Skipping @DatabaseTest expectation due to test exception class org.springframework.transaction.TransactionSystemException
11:46:43.656 [main] DEBUG org.dbunit.database.DatabaseDataSourceConnection - close() - start
11:46:43.657 [main] DEBUG org.springframework.test.context.support.DirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@1da2cb77 testClass = BannerManagerTestCase, testInstance = edu.ucdavis.dss.dw.site.BannerManagerTestCase@48f278eb, testMethod = testCatchesNullDepartment@BannerManagerTestCase, testException = org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction, mergedContextConfiguration = [MergedContextConfiguration@2f217633 testClass = BannerManagerTestCase, locations = '{}', classes = '{class edu.ucdavis.dss.dw.config.TestContextConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class dirties context [false], class mode [null], method dirties context [false].
11:46:43.675 [main] DEBUG org.springframework.test.context.support.DirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@1da2cb77 testClass = BannerManagerTestCase, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@2f217633 testClass = BannerManagerTestCase, locations = '{}', classes = '{class edu.ucdavis.dss.dw.config.TestContextConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], dirtiesContext [false].
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 7.299 sec <<< FAILURE!

Results :

Tests in error: 
  testCatchesNullDepartment(edu.ucdavis.dss.dw.site.BannerManagerTestCase): Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction

如果我不确定我是否正确阅读 - 我会看到空值部门实体,然后是它正在回滚的信息,但有人会认为它会说明为什么它决定回滚

1 个答案:

答案 0 :(得分:5)

您可以在新事务中运行有问题的方法。不应使用@Transactional(propagation = Propagation.NOT_SUPPORTED),而应使用Propagation.REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRES_NEW)

强制创建新事务。 NOT_SUPPORTED不会导致创建新事务,只会暂停当前事务。

在try / catch块中包含对方法的调用。我不确定你在春天的环境中会得到什么样的Exception。在Java EE中,它将是EJBException

相关问题