在会话范围内具有一个简单的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.test插入}调用函数时,有两件事似乎很奇怪:
1)将@Transactional注释移动到方法创建(int)我得到:
javax.persistence。TransactionRequiredException:JBAS011469:执行此操作需要事务(使用事务或扩展持久性上下文)
2) 改为用@Transactional修饰testInsert(),函数立即返回,但JPA仍在后台线程中更新数据库。该过程需要2分钟才能完成仅50000条记录的INSERT。当关闭进程中的Java EE应用程序服务器时,后台进程停止,因此,在我看来,testInsert()不是事务性的。
我在这里的一般误解是什么?如何正确管理交易?
@javax.transaction.Transactional
是 Java EE 7 中引入的拦截器绑定。CDI 为您的 Bean 注入的代理将拦截带注释的方法调用以将它们包装在事务中。
拦截器不适用于私有方法——我想这是您的示例的主要问题。