Java 在Hibernate中使用saveOrUpdate()创建新记录,而不是更新现有记录
我有一个类用户Java 在Hibernate中使用saveOrUpdate()创建新记录,而不是更新现有记录,java,database,hibernate,orm,Java,Database,Hibernate,Orm,我有一个类用户 class User { int id; String name; } 其中,id是User.hbm.xml中的本机生成器,name是数据库中的主键 在我的数据库中,我保存了一些关于用户的信息 然后我想连接有关用户的此信息 例如,在我的数据库中,我有一行插入到用户值('Bill') Main.java User bill = new User(); bill.setName("Bill"); session.saveOrUpdate(bill); 此代码总是尝试将新
class User {
int id;
String name;
}
其中,id
是User.hbm.xml
中的本机生成器,name
是数据库中的主键
在我的数据库中,我保存了一些关于用户的信息
然后我想连接有关用户的此信息
例如,在我的数据库中,我有一行插入到用户值('Bill')代码>
Main.java
User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);
此代码总是尝试将新的账单
行插入表中,而不是更新现有的账单
行。因此,Id不保存在数据库中
如果在Hibernate中将Id映射为标识符,为什么Id不是de DB中的主键
为什么不在数据库中的“Name”上设置一个唯一的约束,并在Id上创建一个主键约束?您应该使用
更新时更新(对象),以及
会话。保存时保存(对象)
这段代码总是试图将账单插入数据库,而不是在数据库中存在关于账单的行时更新
从Hibernate核心文档部分:
saveOrUpdate()
执行以下操作:
- 如果对象已经是持久的
在此会话中,什么也不做
- 如果另一个对象与
会话具有相同的标识符throw
例外
- 如果对象没有
标识符属性,
save()
it
- 如果对象的标识符具有
分配给新实例化的
对象,
save()
it
- 如果对象是
由
或
,以及
属性值是相同的值
分配给新实例化的
对象,save()
it
- 否则
update()
对象
当您这样做时:
User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);
这个新创建的实例没有分配任何标识符值,saveOrUpdate()
将save()
它,如文档所示。如果这不是您想要的,请将名称
作为主键。因此您需要:
User u1 = new User("Bill");
session.save(u1);
User u2 = new User("Bill");
session.saveOrUpdate(u2);
注意到u1和u2是同一张账单并且只存储一次吗?Hibernate无法知道这些账单是同一个人。它只查看用户u2的id,发现它没有设置,得出应该插入u2的结论,然后尝试并报告异常
SaveOrUpdate保存一个全新的对象和当前附加到会话的已加载对象。这是可行的(假设您在某处有一个findByName方法,并且还有另一个属性,比如说favoriteColor):
但那不是你想要的,对吗
由于实体具有代理主键和单独的业务键(通过唯一性约束强制),问题会变得更糟。如果没有id字段且只有名称作为主键,则可以使用merge()(有关saveOrUpdate vs merge的讨论,请参见):
但是你没有,你需要在id上强制PK约束,在name上强制唯一性。所以你需要一些不同的merge来做到这一点。大致来说,你会喜欢以下几点:
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;
}
第一个问题:如果需要获取名为“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();
如果名称字段是主键。然后,如果您多次设置相同的名称,它将如何创建新记录?可能是您对该概念理解不正确。谢谢您的支持id
是主键,name
具有唯一的构造函数,我们有对象类User,例如:User bill=new User()
和我们从keybord或网站获得的关于bill的属性,我的问题是:如果db中存在bill.name,我们调用update(),那么如何使saveOrUpdate()表示保存bill。是的,你说得对,但我希望hibernate的函数saveOrUpdate()能帮我完成这项工作。我可以在签入的地方编写saveOrUpdate(),选择数据库中是否存在name
,然后调用save()或update()。我认为这不是一个好主意,也许hibernate有更好的解决方案,例如override equals(),在这里我们比较bussines key.Thx中的元素。对于您的依赖,我明白为什么我的程序总是尝试插入。因为我有一个更快更容易的id,所以我怎么能在不将名称作为主键的情况下做到这一点呢。我可以使用这样的额外选择:User-bill=new-User();法案。集合名称(“法案”);bill.setId(func())
其中func()是一个函数,当带有name='Bill'
的行不存在时,该函数的结果为空,否则返回此行的id号;没有select,我怎么做?职业开发者如何解决这个问题?@kunkanwan:我不知道该如何理解这个“职业开发者”。现在,这并不能激励我进一步帮助你。恐怕你不理解我。我的英语很差。在“Pro developer”一句中,我想知道如何在软件行业解决这个问题(我是一个没有经验的学生),因为我的简单功能加上额外的select不够好。如果我伤害了你,我很抱歉。@kunkanwan好的,没问题。明天我会再回答这个问题。@PascalThivent但若您将名称命名为PK,以后可能需要将其作为另一个表的FK,那个么新表中会有许多名称,和使用ID作为PK相比,这些名称会获得大量的DB
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;
}
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();