我做了一个基于Jsoup的解析器。该解析器处理带有分页的页面。例如,该页面包含 100 个要解析的链接。我创建了一个主循环来进行分页。我需要运行异步任务来解析每个页面上的 100 个项目。据我了解,Jsoup 不支持异步请求处理。处理完每个项目后,我需要将其保存到数据库中。我想避免在插入数据库表期间出现错误(如果可能的话,线程将同时对不同项目使用相同的 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 更好? 解决这个问题的最佳实践是什么? 你觉得怎么样?
最佳答案
如果使用行级锁定应该没问题。让每个插入都是一个事务可能会解决问题,但是考虑到事务作为一个工作单元的整个概念,这会产生影响(即,如果单个插入失败,您是否希望整个运行失败并回滚?)。
此外,如果您使用 UUID 或数据库生成的 id,则不会出现任何冲突问题。
至于如何构建代码,我会考虑为每个任务使用 Runnables 以及线程池执行器。线程太多,系统会因尝试管理所有线程而失去效率。我注意到你正在使用 spring,所以看看 https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
关于java - 并发插入数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44002334/