Spring JPA 使用EntityManager时如何配置多数据源的事物管理

在使用Spring JPA插入数据时 一般使用CrudRepository自带的save方法。但是最近需要定时将云集群里的Scala程序计算的一些指标数据通过消息队列获取后存入本地DB,每次百万级的插入,使用该方法需要3H57min。查看JPA的源码想找个批量插入的方法提高速度。
在Spring Data JPA的源码中看到
Iterable save(Iterable entities);

查看其源码发现,其实现还是通过遍历逐个插入

save源码:

/*
     * (non-Javadoc)
     * @see org.springframework.data.jpa.repository.JpaRepository#save(java.lang.Iterable)
     */
    @Transactional
    public  List save(Iterable entities) {

        List result = new ArrayList();

        if (entities == null) {
            return result;
        }

        for (S entity : entities) {
            result.add(save(entity));
        }

        return result;
    }

通过在网上查找,发现可以通过Spring注解 @PersistenceContext() 实现事物管理 EntityManager 来完成批量插入,具体方法如下

package com.foundersc.ifc.adviser.decision.dao;

import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;

/**
 * Created by weimiantong on 17/6/28.
 */
public abstract class AbstractDao<T> {
    @PersistenceContext()
    protected EntityManager em;

    @Transactional("")
    public void batchInsert(List list) {
        for (int i = 0; i < list.size(); i++) {
            em.persist(list.get(i));
            if (i % 100 == 0) {
                em.flush();
                em.clear();
            }
        }
    }

    @Transactional()
    public void batchUpdate(List list) {
        for (int i = 0; i < list.size(); i++) {
            em.merge(list.get(i));
            if (i % 100 == 0) {
                em.flush();
                em.clear();
            }
        }
    }

}
该方法在service工程里单独跑单元测试是没问题的,百万级的插入缩短到2H23min。

但是当把单元测试通过的Service工程maven依赖到webapp工程进行使用时,由于webapp工程使用了多个Service需要配置多个数据源。启动报了如下错
 Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jcSignalDao': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 6: entityManagerFactory,entityManagerFactory125,entityManagerFactoryFinancial,wxentityManagerFactory,entityManagerFactory_kh,entityManagerFactoryCommunity

jcSignalDao 需要一个事物管理,但是在spring-jpa.xml 中却配置了6个entityManagerFactory 的beam。导致不知道用哪一个。

解决方法:
通过 @Qualifier(“entityManagerFactoryCommunity”) 注解指定目标数据源的管理器即可, 正确写法如下:

package com.foundersc.ifc.adviser.decision.dao;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import java.util.List;

/**
 * Created by weimiantong on 17/6/28.
 */
@Data
public abstract class AbstractDao {
    //@PersistenceContext(name = "entityManagerFactoryCommunity")
    @Autowired
    @Qualifier("entityManagerFactoryCommunity")
    public EntityManagerFactory emfc;

    @Transactional("transactionManagerCommunity")
    public void batchInsert(List list) {
        EntityManager em = emfc.createEntityManager();
        for (int i = 0; i < list.size(); i++) {
            em.persist(list.get(i));
            if (i % 100 == 0) {
                em.flush();
                em.clear();
            }
        }
        em.close();//不关闭可能导致连接池异常
    }

    @Transactional("transactionManagerCommunity")
    public void batchUpdate(List list) {
        EntityManager em = emfc.createEntityManager();
        for (int i = 0; i < list.size(); i++) {
            em.merge(list.get(i));
            if (i % 100 == 0) {
                em.flush();
                em.clear();
            }
        }
        em.close();
    }

}

你可能感兴趣的:(Spring JPA 使用EntityManager时如何配置多数据源的事物管理)