Spring JPA with hibernate: Illegal attempt to associate a collection with two open sessions

124 Views Asked by At

I've seen several different architectural approaches to implementing spring jpa with hibernate. At a high level something that we have in place right now is the following:

Service layer

@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;

   ...

}

However I've noticed that on rare occasions (hard to reproduce) we get the hibernate exception for an "Illegal attempt to associate a collection with two open sessions". I believe this is happening because we have entities with collections (e.g. ManyToOne mappings) that we retrieve from the db, modify, and later try to call saveOrUpdate but the session we retrieved them from is not the same one as the session we are trying to save them to. Which in the above architecture it seems like we find entities with one session but save them in another even though we make the same call to getCurrentSession.

Is this the best pattern to use with these libraries or is another recommended? What could I do to avoid the hibernate exception?

Would switching to using JPA EntityManager be better than just plain hibernate?

1

There are 1 best solutions below

0
Christian Beikov On

Switching to a transaction scoped EntityManger/Session would help. It seems like you are sharing entity objects between threads and while one thread tries to save such a shared entity, the other thread still has an open session to which the collection of the object is connected.

Don't share entity objects between threads, especially not entities that are still managed i.e. attached to their session.