2011-12-09 127 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实体,您必须将它们从会话中分离出来。