将Hibernate EntityManager保存在Runnable中

时间:2013-04-20 11:20:14

标签: java hibernate

我有一个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:

  1. 根据评论 - 我尝试使用em.getTransaction().begin();,但这让我Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT

  2. skirsch建议我应该在其他bean上调用Transactional方法。这就是我实际做的 - 完全按照你的建议。我想让事情更简单,我没有意识到差异,所以我直接在课程Task中演示了这个问题。总而言之,我完全像skirsch建议的那样,但问题仍然存在。

1 个答案:

答案 0 :(得分:1)

由于Spring没有管理你的Runnable,注释它不会产生预期的效果。因此,您需要在Runnable内使用带注释(和Spring管理)的bean,或者需要手动处理txn管理。

使用Spring事务管理

您定义某种服务

@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();