I am working on an API in spring - JPA - Hibernate application. API receives List of Orders which needs to be persisted one by one.
Controller method is like below
bulkUpsert(@RequestBody Orders orders){
for(Order order:orders.getOrders()){
saveOrUpdateOrder(order);
}
}
Service Method is below
@Transactional
saveOrUpdateOrder(Order order){
//do processing and call dao methods to save/update
}
here is my spring config
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory">
<property name="defaultTimeout" value="${jdbc.defaultTransactionTimeout}"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
web xml:
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
Now the issue that I have observing is that as the no of orders passed keep on increasing ,the time to complete the API is exponentially increasing.I wasn't expecting this as I am commiting the orders one by one. IF first 100 orders take around 10 seconds then 900th-1000th orders take more than 1 minute.
Now If I add entitymanager.clear() just after calling saveOrUpdateOrder in the loop of controller method(bulkUpsert), api becomes electric fast.
Though I am happy that issue is resolved but I am baffled as my understanding doesn't match with what has happened.I was expecting that when transaction commits it will flush all the things and everything will start all again for the next transaction.
Is it not so ?
Does entities still remain in the session even when transaction commits ?
In theory you are correct, however as Spring Boot by default enables the OpenEntityManagerInViewInterceptor
which enables the open entitymanager in view pattern. This in turn leads you to a single EntityManager
per request.
This explains the behavior you see as you expect to get a new and fresh EntityManager
per transaction but instead the pre-registered EntityManager
is re-used.
You can solve this by disabling the OpenEntityManagerInViewInterceptor
. Do this by setting the spring.jpa.open-in-view
to false
in the application.properties
file. This might, however, lead to issues with other code which, probably unknowingly, depends op the open entitymanager in view behavior.