如何透過ForkJoinPool和HikariCP將大型JSON檔案批次處理到MySQL?
這是一個Spring Boot應用程式展示案例,它讀取一個相對較大的JSON檔案(200000多行),並使用ForkJoinPoolAPI和HikariCP 透過批處理將其內容插入MySQL 。
關鍵點:
1. 使用MySQL json型別
-- Create the table CREATE TABLE `lots` ( `lot` json DEFAULT NULL ); |
2. 對於MySQL,application.properties您可能希望將以下內容附加到JDBC URL:
- rewriteBatchedStatements=true: 此設定將強制在單個請求中傳送批處理語句;
- cachePrepStmts=true:如果您決定設定啟用快取和是非常有用的 prepStmtCacheSize,prepStmtCacheSqlLimit等為好; 沒有此設定,快取被禁用;
- useServerPrepStmts=true:這樣你就可以切換到伺服器端準備好的語句(可能會帶來顯著的效能提升); 此外,您可以避免PreparedStatement在JDBC驅動程式級別進行模擬;
- 我們使用以下JDBC URL設定: ...?cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true&createDatabaseIfNotExist=true
application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/citylots_db?cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true&createDatabaseIfNotExist=true spring.datasource.username=root spring.datasource.password=root spring.jpa.hibernate.ddl-auto=create spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect spring.jpa.properties.hibernate.jdbc.batch_size = 300 spring.datasource.initialization-mode=always spring.datasource.platform=mysql spring.datasource.hikari.maximumPoolSize=8 spring.datasource.hikari.minimumIdle=8 logging.level.com.zaxxer.hikari.HikariConfig=DEBUG logging.level.com.zaxxer.hikari=TRACE |
注意: 較舊的MySQL版本不能容忍將重寫和伺服器端預處理語句一起啟用。為確保這些陳述仍然有效,請檢視您正在使用的Connector / J的註釋。
- 設定HikariCP以提供許多資料庫連線,以確保資料庫實現最小上下文切換(例如,2 * CPU核心數)
- 此應用程式用於 StopWatch測量將檔案傳輸到資料庫所需的時間
- 要執行應用程式,您必須citylots.zip在當前位置解壓縮; 這是從Internet收集的相對較大的JSON檔案
- 如果要檢視有關批處理的詳細資訊,只需啟用 DatasourceProxyBeanPostProcessor.java元件,取消註釋 @Component; 這是必需的,因為此應用程式依賴於DataSource-Proxy
3. 將JSON檔案讀入一定容量的List,例如,等於或大於批處理資料大小; 預設情況下,批次大小為300行,臨時列表為300 * 64(建議不要用這些值隨意進行實驗!)
@Repository @Transactional @Scope("prototype") public class RecursiveActionRepository extends RecursiveAction { @Value("${spring.jpa.properties.hibernate.jdbc.batch_size}") private int batchSize; @PersistenceContext private EntityManager entityManager; @Autowired private ApplicationContext applicationContext; private final List<String> jsonList; private static final Logger logger = Logger.getLogger(RecursiveActionRepository.class.getName()); private static final String SQL_INSERT = "INSERT INTO lots (lot) VALUES (?)"; public RecursiveActionRepository(List<String> jsonList) { this.jsonList = jsonList; } @Override public void compute() { if (jsonList.size() > batchSize) { ForkJoinTask.invokeAll(createSubtasks()); } else { Session hibernateSession = entityManager.unwrap(Session.class); hibernateSession.doWork(this::insertJson); } } private List<RecursiveActionRepository> createSubtasks() { List<RecursiveActionRepository> subtasks = new ArrayList<>(); int size = jsonList.size(); List<String> jsonListOne = jsonList.subList(0, (size + 1) / 2); List<String> jsonListTwo = jsonList.subList((size + 1) / 2, size); subtasks.add(applicationContext.getBean( RecursiveActionRepository.class, new ArrayList<>(jsonListOne))); subtasks.add(applicationContext.getBean( RecursiveActionRepository.class, new ArrayList<>(jsonListTwo))); return subtasks; } public void insertJson(Connection connection) { try (PreparedStatement preparedStatement = connection.prepareStatement(SQL_INSERT)) { int i = 1; for (String jsonLine : jsonList) { preparedStatement.setString(1, jsonLine); preparedStatement.addBatch(); if (i % batchSize == 0) { preparedStatement.executeBatch(); i = 0; } i++; } if (i > 1) { preparedStatement.executeBatch(); } logger.log(Level.INFO, "Processed by {0}", Thread.currentThread().getName()); } catch (SQLException e) { logger.log(Level.SEVERE, "SQL exception", e); } } } |
4. 列表減半並建立子任務見createSubtasks,直到列表大小小於批次大小(例如,預設小於300)
當列表已滿時,將其分批儲存到MySQL中,清除列表,然後重新填充
原始碼可以在這裡找到。
相關文章
- 如何透過Python將JSON格式檔案匯入redis?PythonJSONRedis
- 如何將 JSON, Text, XML, CSV 資料檔案匯入 MySQLJSONXMLMySql
- 透過bat檔案批次判斷url地址的狀態BAT
- mysql 透過idb 恢復檔案MySql
- 如何將Excel檔案解析為json格式ExcelJSON
- linux 透過xmllint處理xml檔案LinuxXML
- MAUI Blazor 如何透過url使用本地檔案UIBlazor
- 如何將plist檔案或者陣列NSArray轉化為.json檔案?陣列JSON
- 如何讀取和寫入JSON檔案JSON
- 如何透過.dbf檔案還原資料庫資料庫
- vscode如何將所有檔案格式lf批次轉換為crlfVSCode
- 透過trace檔案重新建立控制檔案
- Win10秘笈:如何批次新建檔案和資料夾?Win10
- 透過MySQL Workbench 將 SQL Server 遷移到GreatSQLMySqlServer
- gulp-ejs 如何通過外部 json 檔案傳值JSON
- 如何透過分解和增量更改將單體遷移到微服務?微服務
- 檔案批次查詢複製匯出,按檔名批次查詢檔案,按檔案內容批次查詢檔案
- SPM12之fMRI批次預處理——NII檔案處理
- 透過HHDESK,將windows中的檔案轉移至Linux系統中WindowsLinux
- 在大型軟體專案中如何處理錯誤和異常
- 一分鐘學會在Mac中如何將檔案批次重新命名Mac
- 如何使用 rsync 透過 SSH 恢復部分傳輸的檔案
- 如何透過SQLyog分析MySQL資料庫MySql資料庫
- 透過dns進行檔案下載DNS
- 使用java透過http遞交檔案?JavaHTTP
- js 透過連結下載檔案JS
- 透過命令列修改nacos配置檔案命令列
- .txt檔案透過Excel拆分行/列Excel
- win10批次檔案改名方法 win10系統下如何批次重新命名檔案Win10
- 報表如何批次匯出成 excel 檔案Excel
- 如何批次對檔案進行重新命名?
- 如何使用find和xargs查詢和處理檔案
- 透過移動資料檔案來均衡檔案I/O
- 通過mysqlimport定時將遠端文字檔案匯入mysqlMySqlImport
- 批次刪除檔案
- 透過 Canal 將 MySQL 資料實時同步到 EasysearchMySql
- Win10如何批次重新命名檔案 Win10批次重新命名檔案教程詳解Win10
- 基於paramiko的檔案批次分發和命令批次執行