我有一个基于hibernate 4的系统。我在表中有一个唯一的约束,需要按照以下方式处理它:
try{
getMyService().create(myobj);
}catch(PersistenceException p){
//constraint fails
myobj.setConstraintColumn("new non unique value");
getMyService().create(myobj);//should save it
}
不幸的是,我无法改变系统的设计,所以我只需要这样解决。
修改
我得到以下异常:
org.hibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs)
创建方法的代码:
public E create(E entity) {
entityManager.persist(entity);
entityManager.flush();
entityManager.refresh(entity);
return entity;
}
答案 0 :(得分:1)
目前尚不清楚您的交易边界在哪里。 抛出异常时,您需要: 1)确保第一个事务已关闭(它应该是,但不确定 - 看看你是否单独尝试#2的嵌套事务) 2)在能够再次持续/刷新(并随后提交)之前开始新事务。
答案 1 :(得分:0)
我终于弄明白了这个问题。所以,让我逐一解释。 首先,看看
Propagation.REQUIRES_NEW does not create a new transaction in Spring with JPA
然后,例如,我们有一个类和方法,如:
public class MyClass{
@Transactional
public void myMethod(){
....
}
}
所以,首先让我们考虑myMethod完全在它自己的事务中,因为事务是基于AOP的,并且它将在适当的方面触发时提交,但只有在方法完成后,抛出异常等等所以我们不能部分提交,部分回滚,不完全回滚等等。因此,我们需要执行以下操作:
因此,在这种情况下,我们创建一个类:
public class ServiceHelper{
@Transational(proparation = **Propagation.REQUIRED_NEW**)
public void tryConstraint throws MyConstraintException{
try{
//insert
}catch(ConstraintViolationException e){
throw new MyConstraintException(e);
}catch(Exception ex){
throw new Exception(ex);
}
}
@Transational(proparation = **Propagation.REQUIRED_NEW**)
public void insertWithNoConflict throws Exception {
//Set new data
//insert, if still CVE or anything other, just throw it , or leave it for unchecked exceptions then
}
}
我们的服务:
public class MyService{
@Autowired
private ServiceHelper serviceHelper;
@Transactional(propagation = **Propagation.REGUIRED_NEW**)
public void createWithCheck(){
try{
serviceHelper.tryConstraint();
}catch(MyConstraintException e){
serviceHelper.insertWithNoConflict();
}
}
}
但是仍然有一种奇怪的情况,因为我需要使用MyService方法在ServiceHelper中创建记录,但是我无法在那里获取它们因为它会导致循环注入,所以我必须通过服务工厂来获取它们:
MyService service = (MyService)ServicesFactory.getInstance().getBean(MyService.BEAN_ID)
我不喜欢它。但这种方法有效,我今天检查过。
我们应该知道两件事:首先我们无法对方法中的事务做任何事情,我们无法在那里开始任何新事务等。事务上下文完全与方法相关,在方法结束之前它仍然存在。第二件事是当我们从同一代理类的方法启动方法时,required_new不起作用。