CDI事务管理:@Transactional是如何工作的



在会话范围内使用一个简单的CDI bean并注入实体管理器:

@Named("myBean")
@SessionScoped
public class MyBean implements Serializable {
    private static final long serialVersionUID = 1L;
    @Inject
    EntityManager em;
   ...
    @Transactional
    private void testInsert() {
        long t = System.currentTimeMillis();
        for (int i=1; i<50000; i++) {  
            create(i);
        }
       System.out.println("Time: " + Long.toString(System.currentTimeMillis()-t));
    }
    private void create(int i) {
        Project p = new Project("Project " + i);
        em.persist(p);
    }
}

现在,当通过EL #{myBean调用函数时。testInsert}有两件事看起来很奇怪:

1)将@ transaction -annotation移动到create(int)方法中,我得到:

javax.persistence。TransactionRequiredException: JBAS011469:事务来执行此操作(或者使用事务或扩展持久化上下文)

2)用@Transactional代替修饰testInsert(),函数立即返回,但是JPA仍然在后台线程中更新数据库。该进程只需要2分钟就可以完成对50000条记录的INSERT。当在进程中关闭Java ee应用程序服务器时,后台进程停止,因此-在我看来- testInsert()不是事务性的。

我在这里的普遍误解是什么?如何正确管理事务?

@javax.transaction.Transactional是Java EE 7中引入的拦截器绑定。CDI为bean注入的代理将拦截带注释的方法调用,以将它们包装在事务中。

拦截器不能用于私有方法——我想这是你的例子的主要问题。

最新更新