我有一个bean,在其中我用Runnable创建一个新的Thread:
@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();
}
}
}
}
使用init方法,使用EntityManager实例创建新的Thread。当我尝试从存储库加载某些内容时,会话立即关闭,并且获取任何延迟字段会导致Hibernate发生failed to lazily initialize a collection of role: Something, no session or session was closed
异常。
我尝试了所有@Transactional注释没有效果。我需要实现像OpenEntityManagerInView这样的东西,但区别在于它不在视图中。
由于
EDIT1:
根据评论 - 我尝试使用em.getTransaction().begin();
,但这让我Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT
。
skirsch建议我应该在其他bean上调用Transactional方法。这就是我实际做的 - 完全按照你的建议。我想让事情更简单,我没有意识到差异,所以我直接在课程Task
中演示了这个问题。总而言之,我完全像skirsch建议的那样,但问题仍然存在。
答案 0 :(得分:1)
由于Spring没有管理你的Runnable
,注释它不会产生预期的效果。因此,您需要在Runnable
内使用带注释(和Spring管理)的bean,或者需要手动处理txn管理。
您定义某种服务
@Service
public class MyService {
@PersistenceContext
EntityManager em;
@Transactional
public void doSomething() {
Thing t = em.findById(...);
t.getSomethingList();
}
}
然后你的bean看起来像这样:
@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();
}
}
}
}
如果您设置了JPA资源本地交易,请转到:
// working with EntityManager
em.getTransaction().begin()
try {
Thing t = em.findById(...);
t.getSomethingList();
} finally {
em.getTransaction().rollback()
}
wait();