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

kun*_*wan 16 java database orm hibernate

我有一个类用户

class User { 
  int id;
  String name;
}
Run Code Online (Sandbox Code Playgroud)

其中id是本机生成器,User.hbm.xml 并且name是DB中的主键.

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

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

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

Main.java

User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);
Run Code Online (Sandbox Code Playgroud)

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

Pas*_*ent 30

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

10.7.Hibernate核心文档的自动状态检测:

saveOrUpdate() 执行以下操作:

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

当你这样做时:

User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);
Run Code Online (Sandbox Code Playgroud)

这个新创建的实例没有分配任何标识值和saveOrUpdate()save()其作为记录.如果这不是您想要的,请创建name主键.


wal*_*orn 17

所以你要:

User u1 = new User("Bill");
session.save(u1);
User u2 = new User("Bill");
session.saveOrUpdate(u2);
Run Code Online (Sandbox Code Playgroud)

注意到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);
Run Code Online (Sandbox Code Playgroud)

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

您的实体具有代理主键和单独的业务键(通过唯一性约束强制执行)会使您的问题变得更糟.如果您没有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);
Run Code Online (Sandbox Code Playgroud)

但是你没有这个,你需要强制执行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;
}
Run Code Online (Sandbox Code Playgroud)


Fre*_*els 1

那么,Id 没有保存在数据库中吗?

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

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