Spring JPA with hibernate:非法尝试将一个集合与两个打开的会话关联



我已经看到了使用hibernate实现spring jpa的几种不同的体系结构方法。在较高的层次上,我们现在所做的是:

服务层

@Service("personService")
public class PersonServiceImpl implements PersonService {
@Autowired
private PersonDao personDao

@Override
@Transactional(readOnly=false, propagation=Propagation.REQUIRES_NEW)
public void save(Person person){
personDao.save(person);
}

@Override
public Person findPerson(BigDecimal id){
return personDao.findPerson(id);
}
...
}

DAO/Repository

import ...
@Repository("personRepository")
public class PersonDaoImpl implements PersonDao {
@Autowired
private SessionFactory sessionFactory;
@Override
public void save(Person person){
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(person);
}

@Override
public Person findPerson(BigDecimal id){
Session session = sessionFactory.getCurrentSession();
return session.get(Person.class, id);
}

...
}

POJO/Entity

import ...
@Entity
@Table(name="PERSON"
)
@Getter
@Setter
public class Person {
@Id
@SequenceGenerator(name="PersonSeq", sequenceName="PERSON_SEQ")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "PersonSeq")
@Column(name="PERSON_ID", nullable=false, precision=22, scale=0)
private BigDecimal id;
...
}

然而,我注意到在极少数情况下(很难重现),我们会因为"非法尝试将一个集合与两个打开的会话关联"而得到hibernate异常。我相信这是发生的,因为我们有实体与集合(例如ManyToOne映射),我们从数据库检索,修改,后来尝试调用saveOrUpdate,但我们检索他们的会话是不一样的会话,我们试图保存他们。在上面的架构中,似乎我们找到了一个会话的实体,但将它们保存在另一个会话中,即使我们对getCurrentSession进行了相同的调用。

这是与这些库一起使用的最佳模式还是推荐使用其他模式?如何避免hibernate异常?

切换到使用JPA EntityManager比只是简单的hibernate更好吗?

切换到事务范围为EntityManger/Session将有所帮助。看起来你在线程之间共享实体对象,当一个线程试图保存这样一个共享实体时,另一个线程仍然有一个打开的会话,该会话连接的对象集合。

不要在线程之间共享实体对象,特别是那些仍然被管理的实体,即连接到它们的会话。

最新更新