使用Java进行BULK INSERT的最佳方法是什么?

时间:2013-07-21 14:02:52

标签: java spring hibernate insert bulk

我正在尝试创建一个可以在数据库中保存大量结构化对象的应用程序。 现在我使用Spring Data JPA(使用hibernate + MySQL(MyIsam表+外键)) 使用Spring Data存储库编写数据服务代码既简单又令人愉快,但性能太慢。

例如,我尝试在一个表中插入100条记录,这需要8,5秒。

我尝试在MySQL cmd中直接执行相同的插入操作(在过程中使用硬编码的“插入字符串”),它显示我的时间 - 0,85秒。即使这样的结果对我来说太慢了,但这是MySQL的问题

阅读论坛我发现post表示Spring Data JPA无法正确进行批量插入。

如何让我的应用更快?我想使用大小为1000或更多的批量INSERT操作。

由于我无法在一个批量中将我的对象存储到db(尽管批量大小),情况变得复杂。

更清楚:

The objectGame contains list of objectRound
The objectGame also contains list of objectGamePlayer
The objectRound contains list of objectRoundCard
The objectGamePlayer contains list of objectPlayerCard
The objectGamePlayer also contains list of objectPlayerBet

当然,要插入objectGame,需要执行以下几个步骤: 插入大量的objectGame并获取它们的ID 让objectGame的Ids插入大量的objectRound并获取它们的ID ......等等

哪种方式更适合我?

使用Spring Data JPA,jdbc,hibernate,myBatis?或者另一种方式?

1 个答案:

答案 0 :(得分:0)

您是对的,Spring Data JPA 默认情况下不会以有效的方式进行批量插入。当我们想将超过 25000 个对象批量写入一个表时,我们遇到了这个问题,而我们有 8 个这样的表要写入。这是我们如何做到的。

默认情况下,Spring Data JPA 会将对象提取到 EntityManager 的缓存中,然后比较并决定是调用persist 还是merge。我绕过了这个逻辑,因为我根据版本知道我是要坚持还是合并。诀窍是根据 if (entity.getVersion() == 0) {

public List<T> update(Collection<T> entities) {
        List<T> ret =  new ArrayList<>();
        EntityManager em = getEntityManager();
        for (T entity : entities) {
            if (entity.getVersion() == 0) {
                em.persist(entity);
                ret.add(entity);
            } else {
                ret.add(em.merge(entity));
            }
        }
        return ret;
    }

您需要 EntityManager 的句柄,您可以通过创建您自己的 JPA Repository 实现来获取它,只需扩展 SimpleJpaRepository 类即可。

import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;

public class MyJpaRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> {

    private EntityManager entityManager;

    public MyJpaRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        
        // Keep the EntityManager around to used from the newly introduced methods.
        this.entityManager = entityManager;
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }
}

并在应用程序的 SpringConfig 上添加以下注释以使用 @EnableJpaRepositories(basePackages = "..." , repositoryBaseClass = MyJpaRepositoryImpl.class)

实例化您的 repo 实现而不是默认的 SimpleJpaRepository
@Configuration
@EnableJpaRepositories(basePackages = "au.com.xyz.infrastructure.repositories" , repositoryBaseClass = MyJpaRepositoryImpl.class)
@ComponentScan(basePackages = {"au.com.xyz.infrastructure.repositories.plugin", "au.com.xyz.infrastructure.repositories.external", ...})

public class InfrastructureSpringConfig {