makson
makson

Reputation: 2243

How I can get entitymanager from crudrepository

I use Spring Boot and want to improve perfomance. I must download file with 50000 field in database. Use hibernate. I found solution in Batch inserts. But I don't know how get entitymanager from crudrepository

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

I creatred MyStorageService and want to save my file:

@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();
}

}

If use in MyStorageService

@PersistenceContext
EntityManager entityManager;

I get

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)

If

@Autowired
EntityManager entityManager;

I get

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)

I use base method savefrom crud repository, but want to improve perfomance and use insert. Tell me please how get entitymanager from crudrepository.
Thanks

Upvotes: 7

Views: 8981

Answers (3)

Uresh K
Uresh K

Reputation: 1136

I am not sure of how your spring configuration is set. With a hope this might help, here you go:

If you have set up a bean of org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean in your context xml or @Configuration java file, in that case, you can acquire the entity manager in the following way.

Assume that you declared the above one as follows:

<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>

Now in your service class, you can Autowire the LocalContainerEntityManagerFactoryBean as below.

@Autowired
LocalContainerEntityManagerFactoryBean entityManagerFactory;

In your method, where you want to get access to entity manager, you can do as below:

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

After this, the below code would follow:

Session session = (Session) entityManager.getDelegate();
Transaction tx = session.beginTransaction();
....
...
tx.commit();
session.close();

However, make sure you close the entityManager after you are done with the whole transaction, like below:

entityManager.close();

Hope this helps.

Upvotes: 5

webdizz
webdizz

Reputation: 846

From my point of view there are several potential problems.

  • @Service and @Repository are both stereotype annotations and allows Spring to autodetect annotated classes and to register within a context. The difference is class thus annotated with @Repository is eligible for Spring DataAccessException translation when used in conjunction with a PersistenceExceptionTranslationPostProcessor.
  • If you annotated class with @Transactional you need to make sure that CGLIB is present in your classpath because Spring AOP requires it to create a proxy for classes.
  • Private methods are not accessible by Spring AOP that means when you annotated class with @Transactional it's methods are not within a transactional context

So I'd suggest to separate concerns e.g. remove unnecessary annotations like @Service and @Transactional if you want to manage transaction by yourself, however according to your code it's not necessary unless you will commit within a for loop after each batch complete.

Upvotes: 2

pvpkiran
pvpkiran

Reputation: 27038

Just autowire EntityManager

@Autowired
EntityManager entityManager;

Upvotes: 0

Related Questions