I am having a bean within which I create a new Thread with Runnable:
@Component
public class MyBean {
private final Task task = new Task();
@PersistenceContext
EntityManager em;
@PostConstruct
public void init() {
task.setEntityManager(em);
new Thread(task).start();
}
public static class Task implements Runnable {
@Setter
private EntityManager em;
@Override
public void run() {
while (true) {
// working with EntityManager
Thing t = em.findById(...); // Fetching a Thing from repo
t.getSomethingList(); // LazyInit exception
wait();
}
}
}
}
Withing the init method, new Thread is created with instance of EntityManager. When I try to load something from the repository the session is instantly closed and getting any lazy field results in failed to lazily initialize a collection of role: Something, no session or session was closed
exception from Hibernate.
I tried all the @Transactional annotations with no effect. I need to achieve something like OpenEntityManagerInView, but with the difference that this is not within view.
Thanks
EDIT1:
According to comments - I tried using em.getTransaction().begin();
but this is getting me Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT
.
skirsch suggested that I should invoke Transactional method on some other bean. That is what I actually do - exactly as you suggested. I wanted to make things simpler and I did not realize the difference, so I demostrated the problem directly in the class Task
. So to summarize, I have it exactly like skirsch suggested, but the problem persists.
As Spring is not managing your Runnable
, annotating it won't have the desired effect. So you either need to use an annotated (and Spring-managed) bean from within your Runnable
or you need to take care of the txn management manually.
You define some kind of service
@Service
public class MyService {
@PersistenceContext
EntityManager em;
@Transactional
public void doSomething() {
Thing t = em.findById(...);
t.getSomethingList();
}
}
And then your bean would look like this:
@Component
public class MyBean {
private final Task task = new Task();
@Autowired
MyService service;
@PostConstruct
public void init() {
task.setService(service);
new Thread(task).start();
}
public static class Task implements Runnable {
@Setter
private MyService service;
@Override
public void run() {
while (true) {
service.doSomething();
wait();
}
}
}
}
In case you set up JPA Resource Local Transactions, here you go:
// working with EntityManager
em.getTransaction().begin()
try {
Thing t = em.findById(...);
t.getSomethingList();
} finally {
em.getTransaction().rollback()
}
wait();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.