从CDI到EJB的事务传播

时间:2014-05-29 23:05:03

标签: java-ee jta

我想提交一个包含文件和其他简单字段的表单。因为发送文件并将其保存在文件系统中对于Web层来说是典型的,所以我在CDI托管bean中执行此操作。从这个CDI托管bean我也调用EJB将其他数据存储在数据库中。保存文件可能会失败,因此我使用@Transactional(JEE7)注释了我的CDI bean的方法。我期望的是在保存文件失败时回滚EJB的事务,但事实并非如此。这是正常的行为吗?在这种情况下如何回滚EJB的事务?

@Named
@javax.faces.view.ViewScoped
public class LectureCtrl
{
    @Inject LecturesFacade lecturesFacade;
    @Getter @Setter UploadedFile paper;
    @Getter @Setter Lecture lecture;

    @Transactional(rollbackOn={FileNotFoundException.class})
    public void create(Lecture _lecture) throws MessagingException, IOException
    {
        try{
            Long _lectureId = lecturesFacade.create( _lecture );
            //args: file, path, constant filename "abstract"
            WebUtils.handleFileUpload( this.paper, "conferences/"+lecture.getConference().getId()+"/lectures/"+_lectureId, "abstract" );
        }catch(Exception e){
            System.out.println(e);
            throw e;
        }
    }

    public String onSubmitNewLecture(){
        //JSF-specific code
        this.create(this.lecture);
        //JSF-specific code
    }

}


@Stateless
public class LecturesFacade {
    @PersistenceContext EntityManager em;
    @Inject EmailSubsystem emailSubsystem;

    public Long create( Lecture lecture ) throws MessagingException
    {
        em.persist(lecture);
        em.flush();
        em.refresh(lecture);
        Long id = lecture.getId();
        emailSubsystem.sendEmailOnNewLecture(lecture);
        return id;
    }
}

例外:

INFO:   java.io.FileNotFoundException: C:\konferencje\files\conferences\3\lectures\20\abstract (Access is denied)
    at java.io.FileOutputStream.open(Native Method)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:165)
    at BackingBeans.WebUtils.handleFileUpload(WebUtils.java:154)
    at BackingBeans.LectureCtrl.create(LectureCtrl.java:56)
    ...

WebUtils.handleFileUpload失败时,我还希望回滚lecturesFacade.create所做的更改。

修改

我已使用LectureFacade.create注释了我的@TransactionAttribute(TransactionAttributeType.MANDATORY)方法,并向我抛出javax.ejb.EJBTransactionRequiredException ,因此看起来CDI事务不会传播到EJB事务。 / p>

2 个答案:

答案 0 :(得分:0)

问题是您需要定义回滚事务的已检查异常。 @Transactional注释有一个名为rollbackOn的字段来设置此

所以尝试注释@Transactional(rollbackOn={FileNotFoundException.class}) - 我没有尝试过代码,所以可能会有拼写错误。您需要指定此原因的原因是FileNotFoundException是一个已检查的异常。

请阅读我链接的文档,因为这是使用容器管理事务时最常见的错误之一。

修改

这很奇怪。您可以尝试将IOException添加到rollbackOn吗?如果这不能解决,我会检查:

  1. 您的数据库是否支持交易? (例如,带myisam的mysql不支持事务)
  2. 您的数据库连接是否正确配置为使用事务? (在某些驱动程序上,您可以指定在每个sql语句上执行自动提交)
  3. 您的容器配置正确吗?不幸的是,你没有添加完整的堆栈跟踪,所以我看不到容器是否为LectureCtrl创建了一个事务代理
  4. 您的应用中是否有多个数据源?这仅适用于您已正确配置JTA(标签中提到)

答案 1 :(得分:0)

我刚刚意识到我正在从同一类的非事务方法(onSubmitNewLecture)调用@Transactional方法(create),因此将省略@Transactional拦截器。