2011-12-09 61 views
1

我使用的是Hibernate 3.3.1。
我有一個db表(2個字段:id,name)。使用Hibernate我爲這個表創建了一個類。休眠生成不必要的查詢

@Entity 
@Table(name = "table1") 
public class QTable1 implements Serializable { 

    public QTable1() { 
    } 

    @Id 
    @Column(name = "id") 
    @GeneratedValue(strategy = GenerationType.AUTO) //<- modification: to comment this line 
    private Long id; 

    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    @Column(name = "name") 
    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

} 

更改我要救他們後用session.saveorUpdate,並將其保存ALL行,已加載表格數據庫。即使他們沒有改變:

update table1 set name='a' where id=1 
update table1 set name='b' where id=2 
update table1 set name='cc' where id=3 // only this row changed 

代碼,修改實體:

final QTable1 item = (QTable1) listTable1.getSelectedValue(); 
if (item != null) { 
    item.setName(table1Name.getText()); 
} 

事務代碼:

final Session session = Commons.getSessionFactory().openSession(); 
session.beginTransaction(); 
for (Object o : pool.getTable1List().toArray()) { 
    final QTable1 item = (QTable1) o; 
    session.saveOrUpdate(item); 
} 
session.getTransaction().commit(); 

爲什麼它保存所有的數據?

如果我改變ID的實現(刪除@GeneratedValue(strategy=GenerationType.AUTO)):

@Id 
@Column(name = "id") 
private Long id; 

它僅保存受影響的行。這就是我所期望的。但沒有@GeneratedValue如果我嘗試向表中添加新行,我必須手動指定id,這並不好。

在調試時,我看到使用@GeneratedValue我沒有在會話PersistanceContext中的實體entitySnapshotsByKey,所以它認爲我的實體是新的,並且必須刷新到db。

如何解決這個問題?

UPDATE:

如果我們使用@GeneratedValue註釋session.saveOrUpdate(item)只產生updateinsert查詢。 但是,如果我們使用@GeneratedValue註釋session.saveOrUpdate(item)產生 1)select爲table1的查詢 2)如果比較的對象是相等的,或者如果我們需要生成updateinsert查詢不 3)決定。

現在我不明白爲什麼@GeneratedValue可以防止查詢值。 仍然我不明白爲什麼它使select查詢如果冬眠有內存中選定的行的副本(entitySnapshotsByKey)。

但我找到了適合我的溶劑。 我需要的僅僅是用session.merge(item)替換session.saveOrUpdate(item)。它會對select查詢進行隔離並對值進行比較(使用@GeneratedValue或不使用)。唯一的缺點是潛在的大量查詢。

感謝所有。如果你幫我防止產生select查詢,會很高興。

+0

您只向我們展示了部分代碼。你能否展示QTable1類的其餘部分,修改實體的代碼以及事務配置? –

回答

0

這是預期和記錄的行爲。 saveOrUpdate需要分離(帶有ID)或瞬態實體(不帶ID),然後更新它(如果分離)或保存(如果是瞬態的)。

saveOrUpdate不知道某些字段是否已更改。它只需要一個實體並將其寫入數據庫。

您可以使用merge,它從數據庫中獲取給定ID的實體,然後將所有字段從分離的實體複製到附加的實體(然後在沖洗時將實體寫入數據庫改變)。但是這需要一個select來獲取數據庫,並且能夠比較新狀態和舊狀態。

+0

據我所知,問題不在於使用'saveOrUpdate'本身,而是生成方式鍵的方式改變了'saveOrUpdate'的工作方式。 – ewernli

+0

JB Nizet,如果我們不使用GeneratedValue,'saveOrUpdate'就像'merge'一樣工作。爲什麼? – Malex

0

在較低的3-rd版本的某處,hibernate改變了行爲 - 它不再需要顯式保存加載的實體(當然,如果沒有正確的文檔 - 這會讓我的屁股變大塊) 。您也可以玩未保存的值設置。

如果您想避免保存persisten實體,您必須將它們從會話中分離出來。