简体   繁体   中英

Hibernate, Multithreading and CascadeType.ALL

In a multithreaded environment,

This works

Box box = new Box("B");
Toy t1 = box.addNewToy("t1");
Toy t2 = box.addNewToy("t2");
synchronized (em) {
    em.getTransaction().begin();
    em.persist(t1);
    em.getTransaction().commit();
}
synchronized (em) {
    em.getTransaction().begin();
    em.persist(t2);
    em.getTransaction().commit();
}

But this doesn't

Box box = new Box("B");
Toy t1 = box.addNewToy("t1");
synchronized (em) {
    em.getTransaction().begin();
    em.persist(t1);
    em.getTransaction().commit();
}
Toy t2 = box.addNewToy("t2");
synchronized (em) {
    em.getTransaction().begin();
    em.persist(t2);
    em.getTransaction().commit();
}

I get errors like: "object references an unsaved transient instance", "a different object with the same identifier value was already associated with the session"

Any ideas?

Here is a minimal Maven project that reproduces the problem: http://www.2shared.com/file/bGLmJ6aO/example.html

Details

java version "1.7.0_17", hibernate 4.2.3.Final, Ubuntu 11.04 natty, SQLite

class Toy {
    @ManyToMany(mappedBy="toys",fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    public List<Box> getBoxes() { return boxes; }

    public void setBoxes(List<Box> boxes) { this.boxes = boxes; }
}

class Box {
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    public List<Toy> getToys() { return toys; }

    public void setToys(List<Toy> toys) { this.toys = toys; }

    public Toy addNewToy(String name) {
        Toy toy = new Toy();
        toy.setName(name);
        toy.boxes.add(this);
        toys.add(toy);
        return toy;
    }
}

A EntityManagerFactory is an expensive-to-create, threadsafe object intended to be shared by all application threads. It is created once, usually on application startup.

An EntityManager is an inexpensive, non-threadsafe object that should be used once, for a single business process, a single unit of work, and then discarded. ...

See: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html_single/#transactions-basics

I'm not exactly sure what you're doing but if you're using that same static EntityManager from multiple threads then that's your problem.

The EntityManagerFactory is the thread-safe object you want to share, but you should create a new EntityManager for each request/unit of work being performed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM