首页 > 解决方案 > 如何使用许多 @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()

标签: hibernate

解决方案


解决方案是将子实体转换为仅包含标识符的存根对象,如以下问题所述:

在 Hibernate 中插入/更新具有另一个引用实体的实体

我的代码中的相关位现在如下所示:

    T autoEnumId = ... obtain ID value from cache ...
    ...
    U entity = clazz.newInstance();
    entity.setId(autoEnumId);
    parentEntity.setXXX(entity);
    ...
    session.save(parentEntity);

推荐阅读