如何使用许多@ManyToOne优化Hibernate对象图的插入? [英] How to optimize insert of Hibernate object graphs with many @ManyToOne?

查看:180
本文介绍了如何使用许多@ManyToOne优化Hibernate对象图的插入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有很多具有很多@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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆