ohseekay
ohseekay

Reputation: 805

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?

Upvotes: 1

Views: 97

Answers (1)

Maciej Kowalski
Maciej Kowalski

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

Related Questions