<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
讀200+的CSV/EXCEL檔案,按檔名稱存到不同資料庫
環境
maven + jdk8 + mysql
pom檔案
<dependencies> <!--https://mvnrepository.com/artifact/com.opencsv/opencsv --> <dependency> //讀取csv檔案 <groupId>com.opencsv</groupId> <artifactId>opencsv</artifactId> <version>${opencsv.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mybatis-plus 持久層--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- velocity 模板引擎, Mybatis Plus 程式碼生成器需要 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>${velocity.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
多執行緒處理資料,否則8k萬資料太慢了
建立執行緒池,個數的大小一般取決於自己電腦設定,以及I/O還是CPU密集型。
public static final Integer N_Thread = Runtime.getRuntime().availableProcessors() * 2 + 1;
ExecutorService service = Executors.newFixedThreadPool(N_Thread ); List<CompletableFuture<Void>> futureList = new ArrayList<>();
資料進行分批次處理,如果資料一次過大,可能導致sql拼接失敗或者程式連線超時的問題。
List<AirStationHourEntity> records = new ArrayList<>(table.values()); int basic = 0, total = records.size(); do{ int finalBasic = basic; String finalTableName = tableName; CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> { List<AirStationHourEntity> subRecords = records.subList(finalBasic * 6000, Math.min((1 + finalBasic) * 6000, total)); airStationHourMapper.saveOrUpdateBatch(finalTableName, subRecords); }, service); // 加入執行緒集合,方便後續阻塞主執行緒,防止執行緒沒跑就提前結束 futureList.add(completableFuture); basic++; }while (basic * 6000 < total);
獲取檔案資料
String url = dataConfig.getStation(); List<String> stationFiles = FileUtils.findFiles(url); //遍歷檔案 for (String fileName : stationFiles) { try { // 讀取檔案資料 String path = url.concat(fileName); CSVReader reader = new CSVReader(new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8)); List<String[]> lines = reader.readAll();
根據檔名建立相應資料庫
tableName = fileName.substring(fileName.lastIndexOf("_") + 1, fileName.indexOf(".") - 2); tableName = TABLE_PREFIX.STATION_PREFIX.value.concat(tableName); if (airStationHourMapper.findTableByName(tableName) == 0) { airStationHourMapper.createNewTable(tableName); }
注意:如果在主執行緒完成之後,沒有對主執行緒進行阻塞,會導致執行緒池中的執行緒沒跑完就直接結束了,需要遍歷執行緒集合來阻塞主執行緒
for (CompletableFuture<Void> future : futureList) { future.join(); }
saveOrUpdateBatch
這裡選用Mysql提供的ON DUPLICATE KEY UPDATE來實現更新或者插入,如果primary key 或者 unique key不存在就插入,否則就更新。注意:primary key 和 unique key都存在的時候可能會導致資料的更新的異常,這裡建議選其中一個最為鍵,否則容易死鎖!見方案選型
<update id="saveOrUpdateBatch"> insert into ${tableName} ( <include refid="Base_Column_List"/> ) values <foreach collection="records" item="record" separator=","> ( #{record.dataId,jdbcType=VARCHAR}, #{record.stationId,jdbcType=VARCHAR}, #{record.dataTime,jdbcType=TIMESTAMP}, #{record.aqi,jdbcType=INTEGER}, #{record.priPol,jdbcType=VARCHAR}, #{record.co,jdbcType=DOUBLE}, #{record.co24,jdbcType=DOUBLE}, #{record.no2,jdbcType=INTEGER}, #{record.no224,jdbcType=INTEGER}, #{record.so2,jdbcType=INTEGER}, #{record.so224,jdbcType=INTEGER}, #{record.o3,jdbcType=INTEGER}, #{record.o324,jdbcType=INTEGER}, #{record.o38,jdbcType=INTEGER}, #{record.o3824,jdbcType=INTEGER}, #{record.pm10,jdbcType=INTEGER}, #{record.pm1024,jdbcType=INTEGER}, #{record.pm25,jdbcType=INTEGER}, #{record.pm2524,jdbcType=INTEGER} ) </foreach> ON DUPLICATE KEY UPDATE AQI = VALUES(AQI),pri_pol = VALUES(pri_pol), CO = VALUES(CO),CO_24 = VALUES(CO_24), NO2 = VALUES(NO2),NO2_24 = VALUES(NO2_24), SO2 = VALUES(SO2),SO2_24 = VALUES(SO2_24), O3 = VALUES(O3),O3_8 = VALUES(O3_8),O3_8_24 = VALUES(O3_8_24), PM10 = VALUES(PM10),PM10_24 = VALUES(PM10_24), PM2_5 = VALUES(PM2_5),PM2_5_24 =VALUES(PM2_5_24); </update>
此方案時間過久,10多個小時大概能完成100w+的資料;
在程式中查詢資料庫中現存的資料,然後對這些資料進行更新,其餘的進行插入
此方案程式程式碼看起來較繁瑣。
選用 ON DUPLICATE KEY UPDATE & 多執行緒來實現批次處理。 問題 在處理最後一些資料時,報異常:獲取不到資料庫連線,連線超時
解決方案
修改application.yml的sql設定
hikari: connection-timeout: 600000 //時間設的長一些
當即存在primary key 以及 unique key時,出現了死鎖
如果一個表定義有多個唯一鍵(包括唯一索引、主鍵)時,是不安全的。
當mysql執行INSERT ON DUPLICATE KEY的INSERT時,儲存引擎會檢查插入的行為是否產生重複錯誤。
org.springframework.dao.DeadlockLoserDataAccessException: ### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction ### The error may exist in class path resource [mapper/PersonGroupRefMapper.xml] ### The error may involve com.order.addOrder-Inline ### The error occurred while setting parameters ### SQL: insert into t_***(XX,XX,XX,XX,XX,XX) values (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE XX= VALUES(XX), XX= VALUES(XX), XX= VALUES(XX) ### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transactio
解決方案
見上面關鍵SQL,刪除了primary key 留下了unique key重新建表。
見上面關鍵SQL,刪除了primary key 留下了unique key重新建表。
批次資料入庫,當SQL語句拼接過長,超過了設定的最大的限制。
解決方案
批次資料入庫時,稍微減少資料量再進行插入,如6000條資料減為4000資料之後再批次入庫。
執行結果
相比之前一天200W+資料有了質的提升,半小時完成了所有資料的預處理以及入庫。
到此這篇關於java之CSV大批次資料入庫的實現的文章就介紹到這了,更多相關java CSV大批次入庫內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45