在Hibernate中使用saveOrUpdate()创建新记录而不是更新现有记录

时间:2010-05-18 13:05:55

标签: java database hibernate orm

我有一个用户类

class User { 
  int id;
  String name;
}

其中idUser.hbm.xml中的本机生成器,而name是DB中的主键。

在我的数据库中,我保存了一些有关用户的信息。

我想要连接有关用户的这些信息。

例如,在我的数据库中,我有一行INSERT INTO User VALUES ('Bill');

Main.java

User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);

此代码始终尝试在表中插入新的Bill行,而不是更新现有的Bill行。

6 个答案:

答案 0 :(得分:29)

  

此代码总是尝试向数据库插入帐单,而不是在DB中存在关于Bill的行时更新...

来自Hibernate核心文档的10.7. Automatic state detection部分:

  

saveOrUpdate()执行以下操作:

     
      
  • 如果对象已经持久化   在这个会话中,什么都不做
  •   
  • 如果另一个对象与...相关联   session具有相同的标识符,throw   例外
  •   
  • 如果对象没有   标识符属性,save()
  •   
  • 如果对象的标识符具有值   分配给新实例化的   对象,save()
  •   
  • 如果对象是   版本为<version>或   <timestamp>和版本   属性值是相同的值   分配给新实例化的   对象,save()
  •   
  • ,否则   update()对象
  •   

当你这样做时:

User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);

这个新创建的实例没有分配任何标识符值,saveOrUpdate()save(),如文档所述。如果这不是您想要的,请将name设为主键。

答案 1 :(得分:15)

所以你想要:

User u1 = new User("Bill");
session.save(u1);
User u2 = new User("Bill");
session.saveOrUpdate(u2);

注意到u1和u2是同一个Bill并且只存储一次? Hibernate无法知道Bills是同一个人。它只查看用户u2的id,看到它没有设置,得出结论:应插入u2,尝试并报告异常。

SaveOrUpdate持久保存全新对象和当前附加到会话的已加载对象。所以这可行(假设你有一个findByName方法,还有另一个属性,让我们说favoriteColor):

User u1 = new User("Bill");
u1.setFavoriteColor("blue");
session.saveOrUpdate(u1);
User u2 = findByName("Joe");
u2.setFavoriteColor("red");
session.saveOrUpdate(u2);

但那不是你想要的,对吗?

您的实体拥有代理主键,并且单独使用业务密钥(通过唯一性约束强制执行)会使您的问题变得更糟。如果您没有id字段且只有名称作为主键,则可以使用merge()(有关saveOrUpdate与merge,look here的讨论):

User u1 = new User("Bill");
u1.setFavoriteColor("blue");
session.save(u1);
User u2 = new User("Bill");
u2.setFavoriteColor("red");
u2 = session.merge(u2);

但是你没有这个,你需要强制执行id的PK约束和名称的唯一性。所以你需要一些合并的变化来做到这一点。非常粗略地说,你会喜欢这些内容:

public User mergeByName(User user) {
    User merged;
    User candidate = findByName(user.getName());
    if (candidate != null) {
        user.setId(candidate.getId());
        merged = session.merge(user);
    } else {
        session.save(user);
        merged = user;
    }
    return merged;
}

答案 2 :(得分:1)

那么,Id不会保存在数据库中吗?

如果你在Hibernate中将它映射为标识符,为什么Id不是de DB中的主键?

为什么不在数据库中对'Name'设置唯一约束,并在Id上创建主键约束?

答案 3 :(得分:1)

第一个问题:如果您需要获取名为“Bill”的用户。你会怎么做?这应该给你一个想法。

要进行更新,您需要具有与用户对象关联的标识。只设置name属性不会有帮助。如果要在没有标识符的情况下进行更新,请使用HQL作为查询。

Query query = session.createQuery("update User u set u.name = :newName where u.name=:name");
query.setString("name", "Bill");
query.setString("newName", "John");
query.executeUpdate();

答案 4 :(得分:-1)

你应该使用 更新时session.update(对象),和 保存期间session.save(对象)

答案 5 :(得分:-3)

如果名称字段是主键。然后,如果您多次设置相同的名称,它将如何创建新记录。 ?可能是你不理解这个概念。