2013-08-01 93 views
1

在多線程環境,休眠,多線程和CascadeType.ALL

這工作

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(); 
} 

但這並不

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(); 
} 

我得到這樣的錯誤:「對象引用未保存的瞬態實例「,」具有相同標識符值的不同對象已經是與會議相關「

任何想法?

下面是一個最小的Maven項目能重現問題:http://www.2shared.com/file/bGLmJ6aO/example.html

詳細

Java版本 「1.7.0_17」,休眠4.2.3.Final,Ubuntu的11.04整潔的,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; 
    } 
} 
+0

第一個代碼塊中是否有拼寫錯誤?沒有t2。 – takteek

回答

1

EntityManagerFactory是一個代價高昂的線程安全對象,旨在被所有應用程序線程共享。它通常在應用程序啓動時創建一次。

一個EntityManager是應該 被使用一次,對於單個的業務流程,工作, 的單個單元,然後被丟棄一種廉價的,非線程對象。 ...

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

我不清楚自己在做什麼,但如果你使用多個線程相同的靜態的EntityManager那麼這是你的問題。

EntityManagerFactory是您想要共享的線程安全對象,但是您應該爲每個正在執行的請求/工作單元創建一個新的EntityManager。

+0

因此,save()前面的「同步」並不真的有幫助嗎?我在多個線程中使用單個EntityManager,但我將其封裝在一個對象中,以確保對它的每次訪問都是原子的。 – neverlastn

+0

entitymanagers應該爲每個業務案例創建,這就是我的想法。 – varun