关于Hibernate:如何从CrudRepository获取EntityManager

How I can get entitymanager from crudrepository

我使用Spring Boot并希望提高性能。 我必须在数据库中下载具有50000字段的文件。 使用休眠模式。 我在批处理插入中找到了解决方案。 但是我不知道如何从CrudRepository获得EntityManager

1
2
3
4
5
6
7
public interface MyRepository extends CrudRepository<OTA, Long>

application.yaml
                jdbc.batch_size: 50
                order_inserts: true
                order_updates: true
                cache.use_second_level_cache: true

我创建了MyStorageService并想保存我的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Service @Repository @Transactional public class MyStorageService {
    private MyRepository myRepository;

    private void insertAll(final List<MyFile> file) {
        myRepository.save(file.getListLine());
    }

private void insert(final List<OTA> ota) {
    Session session = (Session) entityManager.getDelegate();

    Transaction tx = session.beginTransaction();

    for (int i = 0; i < ota.size(); i++) {
        session.save(ota.get(i));
        if (i % 50 == 0) {
            session.flush();
            session.clear();
        }
    }

    tx.commit();
    session.close();
}

}

如果在MyStorageService中使用

1
2
@PersistenceContext
EntityManager entityManager;

我懂了

ERROR [http-nio-18842-exec-1] JpaTransactionManager: Commit exception
overridden by rollback exception java.lang.IllegalStateException:
Transaction not active at
org.hibernate.jpa.internal.TransactionImpl.getRollbackOnly(TransactionImpl.java:131)
at
org.springframework.orm.jpa.JpaTransactionManager$JpaTransactionObject.isRollbackOnly(JpaTransactionManager.java:665)

ERROR [http-nio-18842-exec-1] JpaTransactionManager: Commit exception
overridden by rollback exception java.lang.IllegalStateException:
Transaction not active at
org.hibernate.jpa.internal.TransactionImpl.getRollbackOnly(TransactionImpl.java:131)
at
org.springframework.orm.jpa.JpaTransactionManager$JpaTransactionObject.isRollbackOnly(JpaTransactionManager.java:665)

如果

@Autowired
EntityManager实体管理器;

我懂了

ERROR [http-nio-18842-exec-5] JpaTransactionManager: Commit exception
overridden by rollback exception java.lang.IllegalStateException:
Transaction not active at
org.hibernate.jpa.internal.TransactionImpl.getRollbackOnly(TransactionImpl.java:131)
at
org.springframework.orm.jpa.JpaTransactionManager$JpaTransactionObject.isRollbackOnly(JpaTransactionManager.java:665)

java.lang.IllegalStateException: EntityManager is closed at
org.hibernate.jpa.internal.EntityManagerImpl.checkOpen(EntityManagerImpl.java:97)
at
org.hibernate.jpa.internal.EntityManagerImpl.checkOpen(EntityManagerImpl.java:88)
at
org.hibernate.jpa.spi.AbstractEntityManagerImpl.clear(AbstractEntityManagerImpl.java:1382)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347)
at com.sun.proxy.$Proxy91.clear(Unknown Source) at
org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:554)

我使用了来自crud存储库的基本方法save,但想提高性能并使用插入。 请告诉我如何从Crudrepository获取EntityManager。
谢谢


我不确定您的spring配置如何设置。希望这会有所帮助,在这里您可以:

在这种情况下,如果在上下文xml或@Configuration java文件中设置了org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean的bean,则可以通过以下方式获取实体管理器。

假设您声明以上内容如下:

1
2
3
4
5
6
7
8
9
10
11
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSourceRefToBeMentioned"/>
        <property name="packagesToScan" value="package.to.be.mentioned"/>
        <property name="jpaVendorAdapter" ref="hibernateJPAVendorAdapter"/>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

现在,在您的服务类中,您可以如下所示自动装配LocalContainerEntityManagerManagerFactoryBean。

1
2
@Autowired
LocalContainerEntityManagerFactoryBean entityManagerFactory;

在您想要访问实体管理器的方法中,可以执行以下操作:

1
EntityManager entityManager = entityManagerFactory.getObject().createEntityManager();

在此之后,将遵循以下代码:

1
2
3
4
5
6
Session session = (Session) entityManager.getDelegate();
Transaction tx = session.beginTransaction();
....
...
tx.commit();
session.close();

但是,请确保在完成整个事务后关闭entityManager,如下所示:

1
entityManager.close();

希望这可以帮助。


从我的角度来看,存在几个潜在的问题。

  • @Service和@Repository都是构造型注释,并允许Spring自动检测带注释的类并在上下文中注册。区别在于使用@Repository注释的类与PersistenceExceptionTranslationPostProcessor结合使用时可以进行Spring DataAccessException转换。
  • 如果使用@Transactional为类添加注释,则需要确保CGLIB存在于类路径中,因为Spring AOP要求它为类创建代理。
  • Spring AOP无法访问私有方法,这意味着当您使用@Transactional注释类时,其方法不在事务上下文中

因此,我建议将关注点分开,例如如果您想自己管理事务,请删除@Service和@Transactional等不必要的注释,但是根据您的代码,除非您在每个批处理完成后在for循环中提交,否则没有必要。


只需自动连线EntityManager

1
2
@Autowired
EntityManager entityManager;