Reputation: 805
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?
Upvotes: 1
Views: 97
Reputation: 26522
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.
Upvotes: 1