Issue with data insertion while using TaskExecutor - java

In my web services application, I implement asynchronous task executor to insert object in database. But at the first time of insertion it throws below exception.
org.springframework.orm.hibernate3.HibernateSystemException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance:
2nd time when I refresh the url the object is inserted to database successfully.
The problem is with first instance of new request where object is not inserted.
XML file
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"></bean>
</property>
</bean>
I used org.springframework.core.task.SimpleAsyncTaskExecutor / org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor and also child table list are clear(), addall(). But no luck.
If I comment the task executor tag, all new request objects are inserted properly.
In my scenario, I have to implement asynchronous task executor.
RptServiceImp.java
public class RptServiceImp{
#javax.annotation.Resource
private ApplicationEventPublisher applicationEventPublisher;
#Transactional
public void process(final RqstLoad rqstLoad ) {
try {
applicationEventPublisher.publishEvent(new LoggingEvt (this));
}catch(Exception e){
System.out.println("e:: "+e);
e.printStackTrace();
}
}
EventListoner.java
#Component
public class EventListener implements ApplicationListener<LoggingEvt > {
#Autowired
private EvntRptDAO evntRptDAO ;
#Override
public void onApplicationEvent(LoggingEvt evnt) {
final CustResource custRsrc = event.getCustResource();
try {
evntRpt er = new evntRpt (custRsrc);
evntRptDAO.saveAndFlush(er);
}
catch(Exception e){
System.out.println("e:: "+e);
e.printStackTrace();
}
}
}

Related

Background thread throwing HibernateException - "No Hibernate Session bound to thread..."

I need to create a process that will query a webservice to extract information, and then save the data in my database. However, because this process is very time-intensive, I would like to make it run in the background.
Currently, I have a ProcessHandler which is invoked by a button in the UI. This handler creates a Thread which should run the process in the background. However, I am getting HibernateException with the message No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here.
I have defined ProcessHandler in one of the config xml files (there are several) as follows (this is a very generic definition):
<bean class="com.project.ProcessHandler" parent="parentHandler" />
Inside ProcessHandler, the code to invoke this process is also very generic:
Thread t = new Thread(new WorkerThread(alphaManager, bravoManager, charlieManager));
t.start();
This is the current implementation of WorkerThread:
public class WorkerThread implements Runnable {
private Manager alphaManager;
private Manager bravoManager;
private Manager charlieManager;
public WorkerThread() {
this.alphaManager = null;
this.bravoManager = null;
this.charlieManager= null;
}
public WorkerThread(Manager alphaManager, Manager bravoManager, Manager charlieManager) {
this.alphaManager = alphaManager;
this.bravoManager = bravoManager;
this.charlieManager= charlieManager;
}
#Override
public void run() {
// code to query webservice and extract data...
saveToDbMethod(data);
}
#Transactional(propagation = Propagation.REQUIRED)
private void saveToDbMethod(String data) {
// code to process data...
alphaManager.save(entityA);
bravoManager.save(entityB);
charlieManager.save(entityC);
}
}
The default constructor is a leftover from when I tried to define WorkerThread as a bean in (one of) my config xml files.
Can anyone help me by giving me some tips on how to troubleshoot this?
The problem is that you create the Thread manually and expecting it behave like a spring managed bean.
As the ProcessHandler is a legitimate bean, what i would do is following:
1) Create a seaparate service class which would have the managers as dependencies and that #Transactional method:
#Service
public class Service{
private Manager alphaManager;
private Manager bravoManager;
private Manager charlieManager;
public Service(Manager alphaManager, Manager bravoManager, Manager charlieManager) {
this.alphaManager = alphaManager;
this.bravoManager = bravoManager;
this.charlieManager= charlieManager;
}
#Transactional(propagation = Propagation.REQUIRED)
private void saveToDbMethod(String data) {
// code to process data...
alphaManager.save(entityA);
bravoManager.save(entityB);
charlieManager.save(entityC);
}
}
2) Inject the Service into the ProcessHandler:
<bean class="com.project.ProcessHandler" parent="parentHandler">
<property name="service" ref="service">
</bean>
3) Finally pass the Service to the WorkerThread:
public class WorkerThread implements Runnable {
private Service service;
public WorkerThread(Service service) {
this.service = service;
}
#Override
public void run() {
// code to query webservice and extract data...
service.saveToDbMethod(data);
}
}
and:
Thread t = new Thread(new WorkerThread(service));
t.start();
Now your operations should be transactional and within a session.

How to manage two method calls to a DAO from a service layer in single transaction in Spring MVC and Hibernate

In the service layer class in a method i'm calling a delete method and an insert method of a DAO layer as follows.
Service class:
#Service("workflowService")
#Transactional
public class WorkFlowServiceImpl implements WorkFlowService {
#Autowired
WorkFlowDao workFlowDao;
public String deleteSelectedTask(String strWorkFlowName, int intIndex) {
JSONObject res = new JSONObject();
try{
List<WorkflowPermission> listWorkflowPermission = workFlowDao.getWorkFlowPermissionByName(strWorkFlowName);
listWorkflowPermission.remove(intIndex-1);
boolean flag = workFlowDao.deleteWorkFlowPermissionByName(strWorkFlowName);
for(int i =0;i<listWorkflowPermission.size();i++){
listWorkflowPermission.get(i).setOrderNo(i+1);
flag = workFlowDao.createWorkFlowPermission(listWorkflowPermission.get(i));
}
if(flag==true){
res.put("status", "Success");
res.put("message", "Task Deleted Successfully");
}else{
res.put("status", "Fail");
res.put("message", "Cannot Delete Task");
}
}catch (Exception e) {
logger.error(e);
}
return res.toString();
}
}
Here first i'm getting a list from DAO and deleting the entries on that table and using the for loop i'm inserting as new record by changing the order by calling setOrderNO.
DAO class:
#Repository("workflowDao")
public class WorkFlowDaoImpl implements WorkFlowDao {
#Autowired
private SessionFactory sessionFactory;
private Session session;
#Override
public boolean deleteWorkFlowPermissionByName(String strWorkFlowName) {
try{
session = sessionFactory.getCurrentSession();
SQLQuery sqlQuery= session.createSQLQuery("DELETE FROM UPS_ESC_WTL WHERE workflow_name='"+strWorkFlowName+"'");
sqlQuery.executeUpdate();
session.flush();
return true;
}catch(Exception e){
e.printStackTrace();
}
return false;
}
public boolean createWorkFlowPermission(
WorkflowPermission workFlowPermission) {
boolean blStatus = false;
try {
session = sessionFactory.getCurrentSession();
session.saveOrUpdate(workFlowPermission);
session.flush();
blStatus = true;
} catch (Exception e) {
logger.error(e);
throw new DataAccessException();
}
return blStatus;
}
}
While debugging the code i'm getting the list form database and all records from the table gets deleted. While iterating over the list its properly going through the method of inserting the record. But its not reflecting in the db.
I want to handle transaction with rollback for this and to insert the records to db. Also i have added the HibernateTransactionManager in applicationContext.xml
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Can anyone please help me to resolve this issue. Many thanks in advance.
Add the annotation #Transactional to all methods you need to share the same DB transaction, then the rollback would be applied to all operations.
Example
public class ServiceFirstImpl
#Autowired
FirstDao firstDao;
#Autowired
SecondDao secondDao;
#Transactional
public void mixActions(){
firstDao.delete();
secondDao.create();
}
One of your problem is on deleteWorkFlowPermissionByName method
}catch(Exception e){
e.printStackTrace();
}
Becouse the Spring Transaction will do an rollback if the method throw an RuntimeException or one declared exception.
Now your code will not trigger an rollback if there are an exception in deleteWorkFlowPermissionByName method.
It is enough to have #Transactional on the class in your case. Write to the method unless you want to have different transaction type to some methods.

Thread Count always 1 with Spring ThreadPoolTaskExecutor

I need to implement Multi Threaded background process. My project is spring , hibernate based I tried
with below code which uses org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor to
perform the below background operation in multi threaded manner.I need to know why my
thread count always 1 ?
public class UserUpdateProcessor implements InitializingBean {
private ThreadPoolTaskExecutor executor;
public void afterPropertiesSet() throws Exception {
for(int i = 0; i < 10) //added this like after the 1st reply
executor.execute(new UserBackgorundRunner ());
}
}
private class UserBackgorundRunner extends Thread {
public UserBackgorundRunner() {
this.setDaemon(true);
this.setPriority(MIN_PRIORITY);
}
public void run() {
List<User> users = getUserList();;
for (User user : users) {
try {
log.debug("Active count :::::::::::::::::::::::::::::"+executor.getActiveCount());
upgradeUserInBackground(user);
} catch (Exception e) {
LOGGER.warn("Fail to upgrade user");
}
}
}
My spring.xml looks like
<bean id="userThreadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize"><value>10</value></property>
<property name="maxPoolSize"><value>15</value></property>
<property name="queueCapacity"><value>50</value></property>
</bean>
<bean id="userProcessor" class="com.user.UserUpdateProcessor"
autowire="byType">
<property name="executor" ref="userThreadPool" />
</bean>
It is always one because you only ever submit a single Thread to the ThreadPoolTaskExecutor.
Spring's InitializingBean (JavaDoc link) method afterPropertiesSet() is only invoked once in the Applications lifetime, and as far as I can tell from the example you have provided, that is the only thing submitting Thread's to your ThreadPoolTaskExecutor.

org.hibernate.HibernateException: Current transaction is not in progress

Hi I'm trying to Process some Employees objects and Persist in Database. The Service layer may get an exception from DAO layer. But I still need to process other employee records.
Please look the below Class Example. Here Class A.processEmployees() calls other class EmpHandler which calls DAO. Even if some exception came for an employee, I need other Employees to be processed and Persisted in Database. However, I'm getting Exception as org.hibernate.HibernateException: Current transaction is not in progress
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
Class A
{
public void processEmployees(List<Employee> empList)
{
for (Employee emp : empList)
new EmpHandler().processEmployee(emp);
}
}
You create EmpHandler by call the new method. Therefore that's methods do not handle by Spring Framework and some other containers. You do not should create the EmpHandler object by yourself. Spring Framework should create this object.
You can do following:
Class A
{
private IEmpHandler handler;
public void setEmpHandler(IEmpHandler handler) {
this.handler = handler;
}
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void processEmployees(List<Employee> empList)
{
for (Employee emp : empList)
handler.processEmployee(emp);
}
}
class EmpHandler implements IEmpHandler {
#Override
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void processEmployee(...) {
}
}
In your context.xml:
<bean id="handler" class="...EmpHandler"/>
<bean id="a" class = "...A">
<property name="handler" ref="handler"/>
</bean>

jpa #Transactional + ElasticSearchEventListener (PostInsertEventListener...)

I am having a problem related to JPA & some hibernate listeners I configured to index/deindex the Db entities into Elastic Search. The problem is basically that the listener onPostInsert method is called even if I throw an exception in the method where I am persisting an entity and this method is marked as #Transactional(rollbackFor = {Throwable.class}). My configuration is as follows.
The listener class:
public class ElasticSearchEventListener implements PostDeleteEventListener,
PostInsertEventListener, PostUpdateEventListener {
#Override
public void onPostInsert(PostInsertEvent event) {
log.debug("Listener indexing entity");
try {
updateElasticSearch(event.getEntity());
} catch (Exception e) {
log.debug("Error indexing object from listener");
e.printStackTrace();
}
}
.......
}
The listener configured class:
#Service #Log4j
public class ListenerConfigurerImpl implements ListenerConfigurer {
#Autowired
private EntityManagerFactory entityManagerFactory;
#Autowired
private ElasticSearchEventListener listener;
#PostConstruct #Override
public void registerListeners() {
log.debug("Registering event listeners");
HibernateEntityManagerFactory hibernateEntityManagerFactory = (HibernateEntityManagerFactory) this.entityManagerFactory;
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibernateEntityManagerFactory.getSessionFactory();
EventListenerRegistry registry = sessionFactoryImpl.getServiceRegistry().getService(EventListenerRegistry.class);
registry.getEventListenerGroup(EventType.POST_COMMIT_INSERT).appendListener(listener);
.......
}
}
A service class:
#Service #Log4j
public class ConversationServiceImpl implements ConversationService {
#Override
#Transactional(rollbackFor = {Throwable.class})
public void quotePackage(Long userId, CustomQuoteDTO dto) {
......
Conversation conversation = Conversation.createAndAssign(user, agency, type, subject);
conversation = conversationRepository.save(conversation);
Long conversationId = conversation.getId();
if (1 == 1) throw new RuntimeException();
}
}
Based on this configuration, I would be expecting that the conversation entity is not saved neither in the DB nor Elastic Search. The entity is not persisted in the DB which is correct but for some reason the "onPostInsert" is still executing... and I get the entity in Elastic Search even if it is not in the Database.
Any ideas? I am a bit lost.
Thanks in advance.
EDIT 1 ------
I have found this bug from 2006 and it is still open that seems to be my problem: https://hibernate.atlassian.net/browse/HHH-1582
Is this supposed to work this way?
The pull request added here https://hibernate.atlassian.net/browse/HHH-1582 fixes this issue.

Categories