2014-05-11 35 views
1

我有一個基本安排在一定的時間間隔以下服務做到以下幾點:EJB避免很長的事務(Wildfly)

  • 得到的URL列表,從
  • 下載進行下載
  • 將它們保存到磁盤
  • 堅持從他們的位置下載磁盤上產生的實體

這些下載可能會說1-2個小時。從你在我的班級佈局中看到的內容以及從我的理解中可以看出,在整個定期服務期間,我永久處於一個事務處理中。

@Stateless 
public class TimedService { 

    @EJB 
    private Facade facade; 

    @Schedule(hour="*/12") 
    public void run() { 

     List<String> urls = getAllUrls(); 

     urls.forEach(u -> { 
      facade.downloadFromUrl(u); 
     }); 

    } 
} 

@Stateless 
public class Facade { 

    @EJB 
    private Dao dao; 

    public void downloadFromUrl(String url) { 

     //this is the download part that may take a couple of minutes 
     byte[] bytes = NetUtils.getByteArrayFromUrl(url); 

     //if download was succesfull 
     if(bytes != null) { 
      //save the filename to disk 
      String fileName = createFileName(url); 
      Files.write(fileName, bytes); 

      //save entity to the database with the fileName location 
      Entity e = new Entity(fileName); 
      dao.merge(e); 
     } 
    } 
} 

因此,基本上無論是Wildfly超時事務(默認爲5分鐘)還是將其更改爲24小時超時等。

如果我理解正確的話,即使在Facade#downloadFromUrl交易超時可能不會被觸發,因爲一個單一的下載犯規持續這麼久,我仍然在TimedService#run交易,這將是開放的整個期間,它需要所有下載去完成。

那麼是否有更好的方法,而不僅僅是將交易超時調整爲龐大的數字?

+0

那麼,只需使run()方法不是事務性的。 –

+0

我該怎麼做?我對TransactionAttribute符號不是很熟悉。 – ChrisGeo

+0

這就是文檔存在的原因:http://docs.oracle.com/javaee/6/api/javax/ejb/TransactionAttribute.html –

回答

1

一種方法可以使用JMS。如果你是快樂的,每1交易下載,而不是對整個過程的單個事務,你可以有run()將消息發送到一個消息驅動Bean每個URL下載一個在MDB做facade.downloadFromUrl(u);

2

你應該考慮使用ExecutorService或容器管理的線程池多線程下載,如果你的服務器提供它的話。這將提高整體吞吐量。另外一般來說,將事務置於服務級別是一個好主意,以保證操作是原子操作,但在這種情況下,它是後臺任務,因此可以在將數據寫入數據庫時​​進行事務處理。如果一組下載需要是原子的,那麼您可以參與執行程序提交所有下載的結果,以創建所有下載完成後所有數據庫寫入都發生的障礙。