【问题标题】:EJB avoid very long transaction (Wildfly)EJB 避免很长的事务(Wildfly)
【发布时间】:2014-05-11 11:21:26
【问题描述】:

我有以下服务,基本上是在特定的时间间隔安排执行以下操作:

  • 获取要下载的网址列表
  • 执行下载
  • 将它们保存到磁盘
  • 将下载产生的实体保留在磁盘上的位置

这些下载都可能需要 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 事务中,该事务将在整个持续时间内打开 需要所有下载才能完成。

那么除了将事务超时调整到一个巨大的数字之外,还有更好的方法吗?

【问题讨论】:

标签: java transactions ejb


【解决方案1】:

如果您的服务器提供,您应该考虑使用 ExecutorService 或容器管理的线程池对下载进行多线程处理。这将提高整体吞吐量。此外,通常最好将事务置于服务级别以保证操作是原子的,但在这种情况下,它是一个后台任务,因此可以在将数据写入数据库时​​放置事务。如果一组下载需要是原子的,您可以加入所有下载的执行程序提交的结果,以创建在所有下载完成后发生所有数据库写入的屏障。

【讨论】:

    【解决方案2】:

    一种方法可能是使用 JMS。如果您对每次下载 1 个事务而不是整个过程的单个事务感到满意,您可以让 run() 为每个 URL 向 Message Driven Bean 发送消息以在 MDB 中下载一个做facade.downloadFromUrl(u);

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-07
      • 1970-01-01
      • 2017-04-25
      • 1970-01-01
      • 2023-03-29
      • 2011-03-12
      • 2013-01-04
      相关资源
      最近更新 更多