3

我有一个 bean,我在其中创建一个带有 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();
            }
        }
    }
}

使用 init 方法,使用 EntityManager 的实例创建新的线程。当我尝试从存储库加载某些内容时,会话会立即关闭,并且获取任何惰性字段都会导致failed to lazily initialize a collection of role: Something, no session or session was closedHibernate 出现异常。

我尝试了所有 @Transactional 注释,但没有任何效果。我需要实现类似 OpenEntityManagerInView 的东西,但不同的是这不在视图之内。

谢谢

编辑1:

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

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

4

1 回答 1

1

由于 Spring 不管理您的Runnable,因此对其进行注释不会产生预期的效果。所以你要么需要在你的内部使用一个带注释的(和 Spring 管理的)bean,Runnable要么你需要手动处理 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();
于 2013-04-20T11:50:03.597 回答