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

我有一个class级用户

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行。

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

从10.7节。 Hibernate核心文档的自动状态检测 :

saveOrUpdate()执行以下操作:

  • 如果对象在此会话中已经持久化,则不执行任何操作
  • 如果与会话关联的另一个对象具有相同的标识符,则抛出exception
  • 如果对象没有标识符属性,则save()
  • 如果对象的标识符具有分配给新实例化对象的值,则save()
  • 如果对象是由 化的,并且version属性值是分配给新实例化对象的相同值,则save()
  • 否则update()对象

当你这样做时:

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

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

所以你要:

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

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

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 vs merge的讨论,请查看此处 ):

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

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

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

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

第一个问题:如果需要获取名为“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(); 

您应该在更新时使用session.update(object),在保存时使用session.save(object)

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