Spring @Transactional方法引发异常时Hibernate merge()的行为
我想问一下这种行为的原因,因为当运行到SpringSpring @Transactional方法引发异常时Hibernate merge()的行为,spring,hibernate,jpa,transactional,Spring,Hibernate,Jpa,Transactional,我想问一下这种行为的原因,因为当运行到Spring@Transactional方法/类时,我似乎不完全理解Hibernate中的persist()和merge()之间的区别 我有下面的代码应该回滚DB操作,但它没有(整个类被注释为@Transactional): 引发异常时,以下代码不会按预期回滚: @Override public MyBean assignNewFoo(Integer id, Integer idNewFoo) { MyBean bean = myBeanRepos
@Transactional
方法/类时,我似乎不完全理解Hibernate中的persist()
和merge()
之间的区别
我有下面的代码应该回滚DB操作,但它没有(整个类被注释为@Transactional
):
引发异常时,以下代码不会按预期回滚:
@Override
public MyBean assignNewFoo(Integer id, Integer idNewFoo) {
MyBean bean = myBeanRepository.findOne(id);
myBeanRepository.save(bean);
bean.setNewFoo(
fooManagement.findById(idNewFoo)
);
if (true) throw new RuntimeException();
return bean;
}
save()方法来自类org.springframework.data.jpa.repository.support.SimpleParepository
,因此其代码为:
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
myBeanRepository.save(bean)代码>调用不执行任何操作,因为“bean”已经是JPA管理的实体myBeanRepository.save(bean)==bean
只要在中发出的同一事务“findOne”中执行保存,则该值将为真。合并用于将对实体的非托管实例所做的更改应用于托管实例。此代码说明案例合并用于:
MyBean bean = repo.findOne(id);
MyBean anotherInstance = new MyBean();
anotherInstance.setId(id);
anotherInstance.setNewFoo("100");
MyBean managed = repo.save(anotherInstance);
// And now we take a look:
managed == bean; // => true
anotherInstance == managed; // => false
bean.getNewFoo(); // => "100"
// An anotherInstance is still detached while save() call has
// returned us a managed instance ('bean')
根据您引用的JPA规范条目:此处不适用。它说明了非事务性搜索,但您的搜索是在由assignNewFoo
调用启动的事务中执行的
- 您正在从@Transactional方法调用
,并在这个外部@Transactional方法中执行事务应用程序检查。由于您的传播级别是“必需”的,并且在assignNewFoo
调用中未捕获到RuntimeException,因此一旦assignNewFoo
调用完成,事务将被标记为回滚,但实际回滚将在您的事务从方法传播完成后执行assignNewFoo
- 如果您100%确定自己做的一切都是对的,那么这可能是Spring/Provider/DBMS的问题。我无法在最新的Spring Boot+Hibernate 4+HSQLDB上重现这个bug,如果您没有选择,可能值得检查一下
myBeanRepository.save(bean)代码>调用不执行任何操作,因为“bean”已经是JPA管理的实体myBeanRepository.save(bean)==bean
只要在中发出的同一事务“findOne”中执行保存,则该值将为真。合并用于将对实体的非托管实例所做的更改应用于托管实例。此代码说明案例合并用于:
MyBean bean = repo.findOne(id);
MyBean anotherInstance = new MyBean();
anotherInstance.setId(id);
anotherInstance.setNewFoo("100");
MyBean managed = repo.save(anotherInstance);
// And now we take a look:
managed == bean; // => true
anotherInstance == managed; // => false
bean.getNewFoo(); // => "100"
// An anotherInstance is still detached while save() call has
// returned us a managed instance ('bean')
根据您引用的JPA规范条目:此处不适用。它说明了非事务性搜索,但您的搜索是在由assignNewFoo
调用启动的事务中执行的
- 您正在从@Transactional方法调用
,并在这个外部@Transactional方法中执行事务应用程序检查。由于您的传播级别是“必需”的,并且在assignNewFoo
调用中未捕获到RuntimeException,因此一旦assignNewFoo
调用完成,事务将被标记为回滚,但实际回滚将在您的事务从方法传播完成后执行assignNewFoo
- 如果您100%确定自己做的一切都是对的,那么这可能是Spring/Provider/DBMS的问题。我无法在最新的Spring Boot+Hibernate 4+HSQLDB上重现这个bug,如果您没有选择,可能值得检查一下
你能发布全班的代码吗?完成。你认为其他地方有什么问题吗,@AlanHay?你能把全班的代码都发出来吗?完成了。“你认为其他地方出了什么问题吗,@AlanHay?谢谢你的回答,Roman。”。这是非常有用的。我进一步调试并发现,
PersistenceContextType
实际上是扩展的,而不是我所想的事务,因此这是适用于findOne
的文本:“[…]如果使用具有扩展持久性上下文的实体管理器,它们将被管理”,正如您所说的。大约2点。我无法再复制这个,所以我不能说什么。谢谢你的回复,罗曼。这是非常有用的。我进一步调试并发现,PersistenceContextType
实际上是扩展的,而不是我所想的事务,因此这是适用于findOne
的文本:“[…]如果使用具有扩展持久性上下文的实体管理器,它们将被管理”,正如您所说的。大约2点。我无法再次复制这一点,所以我不能说什么。
MyBean bean = repo.findOne(id);
MyBean anotherInstance = new MyBean();
anotherInstance.setId(id);
anotherInstance.setNewFoo("100");
MyBean managed = repo.save(anotherInstance);
// And now we take a look:
managed == bean; // => true
anotherInstance == managed; // => false
bean.getNewFoo(); // => "100"
// An anotherInstance is still detached while save() call has
// returned us a managed instance ('bean')