我尝试在事务中在数据库中插入 2 条记录。第二次插入失败,但在回滚时第一次插入并未被删除:
@Resource
private WebMessageRep rep; //<-- extends JpaRepository
@Transactional
public void test() {
WebMessage wm = new WebMessage(.valid params.);
wm = rep.save(wm);//<-- save is crud save which is transactional by default
WebMessage wm2 = new WebMessage(.invalid params.);
rep.save(wm2);
}
(我还尝试将保存方法替换为: jpaContext.getEntityManagerByManagedType(WebMessage.class).persist(wm); 这样我就不使用增删改查保存,但问题仍然存在)
我启用了事务日志记录以查看发生了什么,我发现:
在调用 test() 之前,会创建一个新事务,因为 @transactional 注释:
Creating new transaction with name [com..data.webmessage.WebMessageServiceImpl.test]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
Opened new EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
调用第一个保存,它会看到第一个事务:
Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
第二次保存也看到第一个事务:
Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com..shared.WebMessage#107]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=1} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
2017-02-22 14:07:22,000 [ main] DEBUG orm.jpa.JpaTransactionManager - Participating in existing transaction
退出 test() 时,提交完成:
Committing JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com..shared.WebMessage#108], EntityKey[com..shared.WebMessage#107]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=2} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
失败:
Column 'text' cannot be null
HHH000010: On release of batch it still contained JDBC statements
HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]
Initiating transaction rollback after commit exception
回滚:
Rolling back JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
奇怪的是,第一条插入的记录仍然在我的数据库(mysql)中。
不确定这是否意味着什么,但在提交时我们有: 插入=可执行列表{大小=2} 但回滚时是: 插入=ExecutableList{size=0}
有人知道为什么它不回滚第一个插入吗?
我的交易配置非常简单:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
启动我的调试器后发现,当尝试回滚时,我的事务不再处于 Activity 状态。让我解释一下:
[JpaTransactionManager.java]
@Override
protected void doRollback(DefaultTransactionStatus status) {
JpaTransactionObject txObject = (JpaTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Rolling back JPA transaction on EntityManager [" +
txObject.getEntityManagerHolder().getEntityManager() + "]");
}
try {
EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction();
if (tx.isActive()) {
tx.rollback();
}
}
catch (PersistenceException ex) {
throw new TransactionSystemException("Could not roll back JPA transaction", ex);
}
finally {
if (!txObject.isNewEntityManagerHolder()) {
// Clear all pending inserts/updates/deletes in the EntityManager.
// Necessary for pre-bound EntityManagers, to avoid inconsistent state.
txObject.getEntityManagerHolder().getEntityManager().clear();
}
}
}
上面代码中的 tx.isActive() 返回 false,这意味着没有执行回滚。
现在最大的问题是为什么我的交易不再活跃?
最佳答案
嗯,问题似乎是mysql,spring data jpa生成的表是myisam类型。
在使用某些类型的事务时,myisam 似乎变得不稳定。
我将表转换为 innodb,现在它可以工作了:当事务失败并且事务回滚时,所有插入的行都将被删除。当表的类型为 myisam 时,不会发生这种情况。
关于java - Spring data jpa嵌套事务回滚不删除插入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42392916/