如何使用许多@ManyToOne优化Hibernate对象图的插入? [英] How to optimize insert of Hibernate object graphs with many @ManyToOne?
问题描述
我有很多具有很多@ManyToOne
关系的对象,我需要将它们插入数据库中.
I have lots of objects with lots of @ManyToOne
relationships and I need to insert lots of them into the database.
我的插入过程遇到了此代码中的瓶颈,这确保了仅创建和重新使用像枚举之类的@ManyToOne
实体的单个实例:
My insert process has hit a bottleneck in this code, which ensures only a single instance of enum-like @ManyToOne
entities are created and re-used:
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;
}
}
这里的问题是数百万次数据库往返,每次往返仅几纳秒,实际上要等上几个小时才能完成该过程.
The problem here is millions of round-trips to the database, which are just a few nanoseconds each, really add up to several hours of waiting for the process to finish.
因此,我然后尝试使用ConcurrentHashMap
缓存值:
So then I tried to cache the values using 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
我相信正在发生的事情是返回了一个尚未缓存到数据库的缓存"对象,因为正在执行写操作的线程会失去与重新使用该对象的线程的竞争. Doh .
I believe what's happening there is that a "cached" object is returned which hasn't been committed to the database yet, as the thread that's doing the write loses the race to the thread that's re-using the object. Doh.
是否可以优化此过程,以免每次调用saveIfAbsent()
都不会引起数据库往返?
Is it possible to optimize this process so that a database round-trip is not incurred for every call to saveIfAbsent()
?
推荐答案
解决方案是将子实体转换为仅包含标识符的存根对象,如以下问题所述:
The solution was to convert the child entities into stub objects that only contain the identifier, as asked in this question:
我的代码中的相关位现在看起来像这样:
The relevant bits in my code now look like this:
T autoEnumId = ... obtain ID value from cache ...
...
U entity = clazz.newInstance();
entity.setId(autoEnumId);
parentEntity.setXXX(entity);
...
session.save(parentEntity);
这篇关于如何使用许多@ManyToOne优化Hibernate对象图的插入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!