Hibernate生成不必要的查询

时间:2011-12-09 00:07:53

标签: java hibernate

我正在使用Hibernate 3.3.1 我在db中有一个表(2个字段:idname)。使用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保存它们,并保存从db加载的所有行。即使他们没有改变:

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。< / p>

如何解决这个问题?

更新:

如果我们使用@GeneratedValue注释session.saveOrUpdate(item)仅生成updateinsert个查询。 但是,如果我们使用@GeneratedValue注释生成session.saveOrUpdate(item) 1){1}}用于table1查询 2)比较对象是否相等 3)决定是否需要生成selectupdate个查询。

现在我无法理解为什么insert会阻止查询值。 如果hibernate在内存中有所选行的副本(@GeneratedValue),我仍然不明白它为什么会进行select查询。

但是我找到了一个适合我的溶剂。 我只需要用entitySnapshotsByKey替换session.saveOrUpdate(item)。它会隔离session.merge(item)查询,并将比较值(使用select或不使用{})。唯一的缺点是潜在的大量查询。

感谢所有人。如果您帮助我阻止生成@GeneratedValue查询,我们将很高兴。

2 个答案:

答案 0 :(得分:0)

在较低的第3版hibernate中某处改变了行为 - 它不再需要显式保存已加载的实体(当然,没有适当的文档 - 如果它认为它们已被更改,这已经让我的屁股变得很大)。您也可以使用未保存的值设置。

如果您想阻止保存持久性实体,则必须将它们从会话中分离出来。

答案 1 :(得分:0)

这是预期和记录的行为。 saveOrUpdate采用分离的(带有ID)或瞬态实体(没有ID),然后更新它(如果它已分离)或保存它(如果它是瞬态的)。

saveOrUpdate不知道某个字段是否已更改。它只需要一个实体并将其写入数据库。

您可以使用merge从数据库中获取具有给定ID的实体,然后将分离实体中的所有字段复制到附加实体(然后在刷新时将实体写入数据库)如果事情发生了变化)。但是这需要一个select来获取数据库,并能够将新状态与旧状态进行比较。