并发插入数据库

时间:2017-05-16 13:05:36

标签: java jsoup spring-batch java.util.concurrent

我基于Jsoup创建了一个解析器。此解析器处理具有分页的页面。例如,该页面包含100个要解析的链接。我创建了一个超越分页的主循环。我需要运行异步任务来解析每个页面上的100个项目。据我了解,Jsoup不支持异步请求处理。处理完每个项目后,我需要将其保存到DB。我希望在插入DB表时避免错误(如果线程将同时对不同的项使用相同的id,如果可能的话)。你能建议什么? 我可以使用简单的Thread实例来解析每个项目:

public class ItemParser extends Thread {
    private String url;
    private MySpringDataJpaRepository repo;

    public ItemParser(String url, MySpringDataJpaRepository repoReference) {
        this.url = url;
        this.repo = repoReference;
    }

    @Override
    public void run() {
        final MyItem item = jsoupParseItem();
        repo.save(item);
    }
}

运行如下:

public class Parser {

    @Autowired
    private MySpringDataJpaRepository repoReference; // <-- SINGLETON

    public static void main(String[] args) {
        int pages = 10000;
        for (int i = 0; i < pages; i++) {
            Document currentPage = Jsoup.parse();
            List<String> links = currentPage.extractLinks(); // contains 100 links to be parsed on each for-loop iteration
            links.forEach(link -> new ItemParser(link, repoReference).start());
        }
    }
}

我知道这段代码不可编辑,我只想告诉你我的想法。

或者也许最好使用Spring Batch? 解决这个问题的最佳做法是什么? 你觉得怎么样?

1 个答案:

答案 0 :(得分:2)

如果使用行级锁定应该没问题。它可能会节省问题,让每个插入都是一个事务,但这会产生影响,因为事务作为一个工作单元的整个概念(即如果单个插入失败,您是否希望整个运行失败并回滚?)。

此外,如果您使用UUID或db生成的ID,则您不会遇到任何冲突问题。

至于如何构造代码,我将看看每个任务使用Runnables,以及线程池执行器。太多的线程和系统将失去效率,试图管理它们。我注意到你正在使用spring,所以看看https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html