首先,做这样的事情并不少见:
DocumentService {
public Document addDocument(int customerId) {
Customer customer = session.getById(Customer.class, customerId);
Document document = new Document();
customer.getDocuments().add(document);
session.update(customer);
return document;
}
}
因此,最终在添加文档之前读取客户可能看起来像是一种性能损失,但如果您不想传递完整的客户对象,那么这是可行的方法。
通常我使用像 CustomerInfo 对象这样的东西,它只存储一些相关信息,如 id、名称、可能是地址等。通常不经常更改的所有内容,如果用户看到陈旧的数据,则并不重要。 (如果很关键,通常使用通知事件/消息来更新相关信息对象)。
现在您可以将这些 CustomerInfo 传递给许多常见的服务方法。如果从数据库加载客户对象,我通常会更新客户信息对象以尽可能保持同步。
这里只有一个规则。由于客户信息可能包含陈旧的数据(其他用户已更改它,您需要验证其有效性。您可以向其引入 @Version 或比较相关属性(如果它们已经更改)。(您使用乐观日志,又名 long用户事务和两个或多个短数据库事务)。
所以最后使用 reattach 是没有错的。
如果您有一个本地嵌入式数据库,并且使用 hibernate 的应用程序是唯一的用户(单用户设置),您可能需要考虑使用单会话方法,在该方法中同步或汇集对会话的每次访问以避免并发事务 /访问数据库。
这样可以确保只有一个对象代表每个“数据库对象/行”。这使得假设每个对象和每个 Info 都与数据库同步变得很容易。只有在会话丢失的情况下,您必须通过将应用程序使用的所有实体重新附加到新会话来进行恢复,以避免出现两个实体对象代表同一数据库行的情况,这在休眠中是不允许的。
总结
- 使用附加没有错。
- 在应用程序中传递实体实例并没有错。
- 记住:Hibernate 通常发出一个选择来刷新对象并验证它代表当前会话/事务看到的当前数据库状态(使用@Version 来降低成本)。
- 您可以使用 CustomerInfo / DocumentInfo 对象来避免传递实体实例以减少内存占用并避免重新加载。
- 如果性能是一个问题,您可以直接使用 id 创建文档,然后使用您从插入 (SQL) 语句中选择的 id 创建 DocumentInfo。这样您就不必重新加载用户或创建文档对象。这只是为了减少内存占用并提高性能,但接缝不是您的问题。
我的建议,只要您没有内存消耗问题,请坚持重新附加。