我想知道,是否建議使用這種方式來使用 jpa 實作 reader spring 批處理,或者尋找另一種解決方案是否更好,如果不建議使用這種方式,我在哪里可以找到有關更好選擇的資訊
public class CreditCardItemReader implements ItemReader<CreditCard> {
@Autowired
private CreditCardRepository respository;
private Iterator<CreditCard> usersIterator;
@BeforeStep
public void before(StepExecution stepExecution) {
usersIterator = respository.someQuery().iterator();
}
@Override
public CreditCard read() {
if (usersIterator != null && usersIterator.hasNext()) {
return usersIterator.next();
} else {
return null;
}
}
}
uj5u.com熱心網友回復:
此實作僅適用于小型資料集,因為資料是通過一個批量查詢讀取的,并將整個結果串列存盤在記憶體中。此外,它不是執行緒安全的。
在加載大容量的情況下:
- 在記憶體有限的環境下會導致記憶體不足
- 可能導致性能問題。我們將等到通過一次呼叫從資料庫加載數千條記錄
解決方案 1,org.springframework.batch.item.database.JpaCursorItemReader
在 Spring Batch 中開箱即用地定義了類似的實作:JpaCursorItemReader
主要區別在于該實作僅適用于特定的 JPQL 查詢而不是存盤庫,并使用 JPA 的Query.getResultStream ()方法獲取查詢結果。
實施JpaCursorItemReader
:
protected void doOpen() throws Exception {
...
Query query = createQuery();
if (this.parameterValues != null) {
this.parameterValues.forEach(query::setParameter);
}
this.iterator = query.getResultStream().iterator();
}
例如,HibernateQuery.getResultStream()
在 5.2 版本中引入了該方法。它使用 Hibernate 的ScrollableResult
實作來遍歷結果集并批量獲取記錄。這可以防止您一次加載結果集的所有記錄,并允許您更有效地處理它們。
創建示例:
protected ItemReader<Foo> getItemReader() throws Exception {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
String jpqlQuery = "from Foo";
JpaCursorItemReader<Foo> itemReader = new JpaCursorItemReader<>();
itemReader.setQueryString(jpqlQuery);
itemReader.setEntityManagerFactory(factoryBean.getObject());
itemReader.afterPropertiesSet();
itemReader.setSaveState(true);
return itemReader;
}
方案二、org.springframework.batch.item.database.JpaPagingItemReader
是JPQL查詢比JpaCursorItemReader
. ItemReader 按頁面加載和存盤資料,它是執行緒安全的。
根據檔案:
ItemReader 用于讀取建立在 JPA 之上的資料庫記錄。
它執行 JPQL setQueryString(String) 以檢索請求的資料。使用 AbstractPagingItemReader.setPageSize(int) 中指定大小的分頁請求執行查詢。當呼叫 AbstractItemCountingItemStreamItemReader.read() 方法時,會在需要時請求其他頁面,回傳與當前位置對應的物件。
分頁的性能取決于 JPA 實作及其使用資料庫特定功能來限制回傳的行數。
設定相當大的頁面大小并使用與頁面大小匹配的提交間隔應該會提供更好的性能。
為了減少大型結果的記憶體使用量,在讀取每個頁面后都會重繪 和清除持久性背景關系。這會導致任何讀取的物體被分離。如果您對物體進行更改并希望保留更改,則必須顯式合并物體。
該實作在呼叫之間是執行緒安全的
方案3,org.springframework.batch.item.data.RepositoryItemReader
是更高效的方案。它與存盤庫一起作業,以塊的形式加載和存盤資料,并且是執行緒安全的。
根據檔案:
使用 PagingAndSortingRepository 讀取記錄的 ItemReader。
閱讀器的性能取決于存盤庫的實作,但是設定一個相當大的頁面大小并將其與提交間隔匹配應該會產生更好的性能。
閱讀器必須配置一個 PagingAndSortingRepository、一個 Sort 和一個大于 0 的 pageSize。
此實作在對 AbstractItemCountingItemStreamItemReader.open(ExecutionContext) 的呼叫之間是執行緒安全的,但如果在多執行緒客戶端中使用(無重新啟動可用),請記住使用 saveState=false。
創建示例:
PagingAndSortingRepository<Foo, Long> repository = FooRepository<>();
RepositoryItemReader<Foo> reader = new RepositoryItemReader<>();
reader.setRepository(repository ); //The PagingAndSortingRepository implementation used to read input from.
reader.setMethodName("findByName"); //Specifies what method on the repository to call.
reader.setArguments(arguments); // Arguments to be passed to the data providing method.
通過構建器創建:
PagingAndSortingRepository<Foo, Long> repository = new FooRepository<>();
new RepositoryItemReaderBuilder<>().repository(repository)
.methodName("findByName")
.arguments(new ArrayList<>())
.build()
更多使用示例:RepositoryItemReaderTests和RepositoryItemReaderIntegrationTests
總結:
您的實作僅適用于簡單的用例。
我建議使用開箱即用的解決方案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/474125.html
上一篇:如何在perform_create中使用Validator來限制DjangoRestFramework的影像上傳大小?
下一篇:無法為物體存盤多對一關聯