EJB 抽象方法的本地调用是否打开一个新事务?

Does local call of an EJB abstract method open a new Transaction?

假设 类 的以下构造:

一个 Filereader 找到文件的匹配导入程序并调用 Importer.import 方法。

这个方法调用了抽象方法importSpecific,被注释为REQUIRES_NEW。

从容器的角度来看,本地调用不会开启新的事务,但从继承的角度,我不确定。

importSpecific 调用 ImporterBase.import 是否创建新交易,为什么会这样?

Class 文件读取器:

@Singleton(name = "FileReader")
public class FileReader extends Traceable {

    /*@Inject
      @Any
      public Instance<Importer> importers;*/

    @EJB
    ExampleImporter importer;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void listenToFileAvailableEvent(@Observes FileAvailable event) throws InterruptedException {        
        for (final String filename : event.getFilenames()) {            
            readFile(filename);
        }
    }

    public void readFile(String filenameWithPath) {
        //[...]-> Extract FileMetadata and find correct importer
        importer.import(dateiMeta);
    }
}

接口导入器:

@Local
public interface Importer {
    void import(FileMetaData dateiMeta) throws Exception;
    void importSpecific(FileMetaData dateiMeta) throws Exception;
}

Class 进口商基地:

public abstract class ImporterBase implements Importer {
   @Resource
   private SessionContext ctx;

   @Override
   public void import(FileMetaData dateiMeta) throws Exception {           
       try {           
          ctx.getBusinessObject(Importer.class).importSpecific(dateiMeta);//This causes the error
       } catch (Exception ex) {            
           //[...] Log Error
           throw ex;
       }        
   }

   @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
   public abstract void importSpecific(FileMetaData dateiMeta) throws   Exception;

}

Class 示例进口商:

@Stateless
public class ExampleImporter extends ImporterBase {

    @Override
    public void importSpecific(FileMetaData dateiMeta) throws Exception {
        //Import from file
    }   
}

不,importSpecific何时(以及如何)被您的方法调用 import 永远不会打开新事务;因为(如您所说)到容器的始终是本地调用...

但是,根据this,注解@TransactionAttribute是可以继承的...所以,

为了使这种配置起作用,您必须:

1)在你的业务接口声明importSpecific方法,即Importer接口

2) 将 Importer 接口表示为您的本地接口。

3) 在您的 FileReader 单例中,使用 @EJB 注释获取您的 Importer Bean 的代理。如果您使用 CDI 注释(如 @Inject),容器将注入 CDI 对象而不是 EJB 代理! (注意这个)

4) 将您的 ImporterBase 代码更改为:

public abstract class ImporterBase implements Importer {
    @Resource
    private SessionContext ejbCtxt;

    @Override
    public void import(FileMetaData dateiMeta) throws Exception {
        Importer proxy0;    
        try {           
            proxy0 = this.ejbCtxt.getBusinessObject(Importer.class);
            proxy0.importSpecific(dateiMeta);

        } catch (Exception ex) {            
            //[...] Log Error
            throw ex;
        }        
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public abstract void importSpecific(FileMetaData dateiMeta) throws Exception;

}

5) 像这样更改您的 ExampleImporter

@Stateless
@Local(Importer.class)
public class ExampleImporter extends ImportBase {
...
}

如果你真的需要在你的单例中使用 CDI Bean 而不是 EJB 代理 Class,你将需要使用 @Transactional CDI 注释来代替......你的代码也应该重构.