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

来源:互联网 发布:投资软件靠谱吗 编辑:程序博客网 时间:2024/06/05 11:19

在使用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 <S extends T> List<S> save(Iterable<S> entities) {        List<S> result = new ArrayList<S>();        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<T> 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<T> 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 failedorg.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. */@Datapublic abstract class AbstractDao<T> {    //@PersistenceContext(name = "entityManagerFactoryCommunity")    @Autowired    @Qualifier("entityManagerFactoryCommunity")    public EntityManagerFactory emfc;    @Transactional("transactionManagerCommunity")    public void batchInsert(List<T> 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<T> 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();    }}
原创粉丝点击