我有一个Java程序,需要在SQL Server数据库中插入大量的大行。行数为800k,每个行的大小约为200字节。
目前它们被分成50个批次,然后使用单个语句插入每个批次。 (我们已经通过JTDS记录确认每个批次都使用一个sp_exec调用。)调整25到250之间的批量大小似乎没有任何显着影响,50几乎是最佳的。
我已尝试将批次划分为(例如)5组,并使用线程并行处理每个组。这明显更快 - 使用5个线程的速度快了两倍。
我的问题是如何使线程使用健壮。特别是,如果任何批次失败,则会抛出异常。我希望将该异常捕获并传递给调用者,并且我希望在我们传递之前100%确定其他线程已完成(中止或完成)。因为在程序后期从异常中恢复时,我们不希望意外的行继续到达表中。
这就是我所做的:
/** Method to insert a single batch. */
private void insertBatchPostings(Collection<Posting> postings) throws PostingUpdateException
{
// insert the batch using a single INSERT invokation
// throw a PostingUpdateException if anything goes wrong
}
private static final int insertionThreads = 5;
/** Method to insert a collection of batches in parallel, using the above. */
protected void insertBatchPostingsThreaded(Collection<Collection<Posting>> batches) throws PostingUpdateException
{
ExecutorService pool = Executors.newFixedThreadPool(insertionThreads);
Collection<Future> futures = new ArrayList<Future>(batches.size());
for (final Collection<Posting> batch : batches) {
Callable c = new Callable() {
public Object call() throws PostingUpdateException {
insertBatchPostings(batch);
return null;
}
};
/* So we submit each batch to the pool, and keep a note of its Future so we can check it later. */
futures.add(pool.submit(c));
}
/* Pool is running, indicate that no further work will be submitted to it. */
pool.shutdown();
/* Check all the futures for problems. */
for (Future f : futures) {
try {
f.get();
} catch (InterruptedException ex) {
throw new PostingUpdateException("Interrupted while processing insert results: " + ex.getMessage(), ex);
} catch (ExecutionException ex) {
pool.shutdownNow();
throw (PostingUpdateException) ex.getCause();
}
}
}
当它返回时我想保证所有线程都处于休眠状态。
问题
(我想澄清一下我到底要问的是什么。)
insertBatchPostingsThreaded
返回后没有线程插入会继续运行?我不是一个天生的Java程序员,所以我希望最终得到一些不会宣传这一事实的东西。 :)
答案 0 :(得分:1)
Guava的Futures.successfulAsList
将期货列表作为输入并返回未来“其价值是包含其所有成功输入期货价值的列表。”您可以在生成的get()
上调用Future
,然后浏览原来的未来列表以检查是否有任何失败。