hibernate - 如何使用许多 @ManyToOne 优化 Hibernate 对象图的插入?
问题描述
我有很多具有很多@ManyToOne
关系的对象,我需要将它们中的很多插入到数据库中。
我的插入过程在这段代码中遇到了瓶颈,它确保只@ManyToOne
创建和重用一个类似枚举的实体实例:
public <U extends AutoEnum<?>> U saveIfAbsent(Session session, Class<U> clazz, U obj) {
if (obj == null || obj.getValue() == null) {
return null;
}
Optional<U> loadOptional = session.byNaturalId(clazz).using("value", obj.getValue()).loadOptional();
if (loadOptional.isPresent()) {
return loadOptional.get();
} else {
session.save(obj);
return obj;
}
}
这里的问题是数百万次到数据库的往返,每次只有几纳秒,实际上加起来需要几个小时的等待过程完成。
因此,我尝试使用 a 缓存值ConcurrentHashMap
:
private Map<String,Object> cache = new ConcurrentHashMap<>();
public <U extends AutoEnum<?>> U saveIfAbsent(Session session, Class<U> clazz, U obj) {
if (obj == null || obj.getValue() == null) {
return null;
}
@SuppressWarnings("unchecked")
U tmp = (U) cache.computeIfAbsent(clazz.getName() + ":" + obj.getValue(), key_ -> {
Optional<U> loadOptional = session.byNaturalId(clazz).using("value", obj.getValue()).loadOptional();
if (loadOptional.isPresent()) {
return loadOptional.get();
} else {
session.save(obj);
return obj;
}
});
return tmp;
}
不幸的是,这失败了:
...SqlExceptionHelper : ERROR: insert or update on table "mytable" violates foreign key constraint
我相信那里发生的事情是返回了一个尚未提交到数据库的“缓存”对象,因为正在执行写入的线程失去了与重新使用该对象的线程的竞争。多哈。
是否可以优化此过程,以便每次调用都不会导致数据库往返saveIfAbsent()
?
解决方案
解决方案是将子实体转换为仅包含标识符的存根对象,如以下问题所述:
我的代码中的相关位现在如下所示:
T autoEnumId = ... obtain ID value from cache ...
...
U entity = clazz.newInstance();
entity.setId(autoEnumId);
parentEntity.setXXX(entity);
...
session.save(parentEntity);
推荐阅读
- vb.net - Outlook 加载项错误
- apache-spark - 使用 Parquet 数据进行 Spark 缓存
- php - API 密钥无效。使用谷歌翻译 api 时出错
- c# - 如何定义查看属性值的样式
- laravel - 如何通过比较数据透视表中的值与 laravel 5.6 中所需表中的值来获取数据?
- node.js - NodeJS 生成 FFMPEG 进程不正确理解参数
- .net - VS 2013/Windows 10:添加/更新服务参考获取消息无法创建 SSL/TLS 安全通道
- git - 即使没有新的更改,也强制推送到 Gerrit
- git - 将 git 分支重置为较早的结帐
- string - 删除 kotlin 中的重音符号和变音符号