springboot+mybatis快速插入大量數(shù)據(jù)的具體實現(xiàn)
前言
在公司業(yè)務開發(fā)過程中,我們經常會遇到往數(shù)據(jù)庫表中插入大量數(shù)據(jù)的場景,比如excel批量導入數(shù)據(jù)。那么該如何快速地插入數(shù)據(jù)呢?我們可以考慮使用批量插入來實現(xiàn),該方案實測每秒能達到35000條,后附具體實現(xiàn)代碼。接下來我就給大家說一下實現(xiàn)方式。
一. JDBC實現(xiàn)方案
用一個 for 循環(huán),把數(shù)據(jù)一條一條地插入;生成一條插入 sql,類似這種 insert into user(name,pwd) values('aa','123'),('cc','123')...
第一種方案,是用 for語句循環(huán)插入:
該方案的優(yōu)勢在于,JDBC 中的 PreparedStatement 有預編譯功能,預編譯之后會緩存起來。之后SQL執(zhí)行會比較快,且 JDBC可以開啟批處理,這個批處理執(zhí)行非常給力。
劣勢在于,很多時候我們的 SQL 服務器和應用服務器可能并不是同一臺,所以必須要考慮網絡 IO。如果網絡 IO 比較費時間的話,那么可能會拖慢 SQL 執(zhí)行的速度。
第二種方案,是生成一條 SQL進行插入:
該方案的優(yōu)勢在于,只有一次網絡 IO。即使分片處理也只是數(shù)次網絡 IO,所以這種方案不會在網絡 IO 上花費太多時間。
當然這種方案也有劣勢。一是 SQL 太長了,甚至可能需要分片后批量處理;二是無法充分發(fā)揮 PreparedStatement 預編譯的優(yōu)勢,SQL 要重新解析且無法復用;三是最終生成的 SQL 太長了,數(shù)據(jù)庫管理器解析這么長的 SQL 也需要時間。
我們接下來會采用第二種方案進行實現(xiàn)。
二. 具體實現(xiàn)思路
如果我們想要拉高插入效率,肯定不能夠一條一條地插入了,必須得使用foreach批量插入;
采用多線程進行異步插入,提升性能;
我們不可能單次提交多個insert,大量的插入操作會很耗時,短時間內完不成,可以采用定時任務來實現(xiàn)。
接下來我們就來說說具體該怎么利用代碼進行實現(xiàn)。
三. 代碼實現(xiàn)
本案例主要是基于SpringBoot整合mybatis進行實現(xiàn)。
1.導入依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.48</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies>
2.創(chuàng)建啟動類
@SpringBootApplication //引導類核心注解 @EnableScheduling //開啟定時任務 public class BatchApplication { public static void main(String[] args) { SpringApplication.run(BatchApplication.class,args); } }
3.配置文件application.yml
server: port: 9999 # 指定端口號 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password: 123 mybatis: mapper-locations: classpath:mybatis/*.xml #指定mapper映射文件路徑 type-aliases-package: com.qfedu.model # 別名
4.創(chuàng)建表與實體類User
創(chuàng)建表:
CREATE TABLE `user` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `username` VARCHAR(30) DEFAULT NULL, `pwd` VARCHAR(20) DEFAULT NULL, `sex` INT(11) DEFAULT NULL, `birthday` DATETIME DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8
注意:MyISAM效率會比INNODB快。
User.java
@Data public class User { private int id; private String username; private String pwd; private int sex; private LocalDate birthday; }
5.持久層mapper和映射文件
UserMapper.java
@Mapper public interface UserMapper { void insertBatch(@Param("userList") List<User> userList); }
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.qfedu.mapper.UserMapper"> <insert id="addList" parameterType="User" > insert into user (username,pwd,sex,birthday) values <foreach collection="list" item="item" separator=","> (#{item.username}, #{item.pwd}, #{item.sex}, #{item.birthday}) </foreach> </insert> </mapper>
6.開啟定時任務
SpringBoot默認整合了scheduled,使用步驟如下:
在引導類加入@EnableScheduling注解,開啟定時任務;
在業(yè)務層方法上加入 @Scheduled注解,定義cron表達式周期執(zhí)行。
業(yè)務層方法中開啟的線程可以根據(jù)當前機器的配置來修改。我們這里開了7個線程,每個線程去執(zhí)行20次循環(huán),一次添加5000條數(shù)據(jù)。這里要注意mybatis批量插入時,不建議超過10000條錯誤。因為數(shù)據(jù)量過大,容易出現(xiàn)棧內存溢出的問題。
@Component public class UserServiceImpl { @Autowired private UserMapper userMapper; @Autowired //線程池 private ThreadPoolExecutor executor; @Scheduled(cron = "0/20 * * * * ?") //每隔20秒執(zhí)行一次 public void addList(){ System.out.println("定時器被觸發(fā)"); long start = System.currentTimeMillis(); for (int i = 0; i < 7; i++) { Thread thread = new Thread(() -> { try { for (int j = 0; j < 20; j++) { userMapper.addList(UserUtil.getUsers(5000)); } } catch (Exception e) { e.printStackTrace(); } }); try { executor.execute(thread); } catch (Exception e) { System.out.println(e.getMessage()); } } } }
7.生成對象的util
我們用來模擬生成要插入的數(shù)據(jù),實際業(yè)務開發(fā)的時候可以是從excel中導入的數(shù)據(jù)。
public class UserUtil { private static Random random = new Random(); public static List<User> getUsers(int num){ List<User> users = new ArrayList<>(); for (int i = 0;i<num;i++){ User user = new User(); user.setBirthday(LocalDate.now()); user.setSex(random.nextInt(2)); user.setPwd("123"+random.nextInt(100000)); user.setUsername("batch"+random.nextInt(num)); users.add(user); } return users; } }
8.線程池配置
線程池參數(shù):
corePoolSize 核心線程數(shù),在線程池中要保證的最小線程數(shù);
mainumPoolSize 最大線程數(shù),線程池中能運行的最大線程數(shù);
keepAliveTime 保證存活時間,當線程空閑時間,多久會回收線程;
unit 和keepAliveTime配合使用,時間單位;
workQueue 工作隊列,用于存儲任務在任務被執(zhí)行之前。
@Configuration public class ThreadPoolExecutorConfig { @Bean public ThreadPoolExecutor threadPoolExecutor() { //線程池中6個線程,最大8個線程,用于緩存任務的阻塞隊列數(shù)5個 ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 8, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100)); executor.allowCoreThreadTimeOut(true);//允許超時 return executor; } }
9.完整項目結構
10.測試
總結
到此這篇關于springboot+mybatis快速插入大量數(shù)據(jù)的文章就介紹到這了,更多相關springboot mybatis快速插入大量數(shù)據(jù)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
idea使用easyCode生成代碼(根據(jù)mybatis-plus模板創(chuàng)建自己的模板)
本文主要介紹了idea使用easyCode生成代碼,easyCode代碼生成器可以減少低價值搬磚,具有一定的參考價值,感興趣的可以了解一下2023-10-10Springboot @Configuration與自動配置詳解
這篇文章主要介紹了SpringBoot中的@Configuration自動配置,在進行項目編寫前,我們還需要知道一個東西,就是SpringBoot對我們的SpringMVC還做了哪些配置,包括如何擴展,如何定制,只有把這些都搞清楚了,我們在之后使用才會更加得心應手2022-07-07springboot整合spring-data-redis遇到的坑
使用springboot整合redis,使用默認的序列化配置,然后使用redis-client去查詢時查詢不到相應的key.問題出在哪,怎么解決呢?下面小編給大家?guī)砹藄pringboot整合spring-data-redis遇到的坑,需要的的朋友參考下吧2017-04-04springboot中mybatis多數(shù)據(jù)源動態(tài)切換實現(xiàn)
在開發(fā)中,動態(tài)數(shù)據(jù)源配置還是用的比較多的,比如在多數(shù)據(jù)源使用方面,又或者是在多個DB之間切換方面。這里給出一個動態(tài)數(shù)據(jù)源的配置方案,感興趣的可以了解一下2021-07-07Spring遠程調用HttpClient/RestTemplate的方法
這篇文章主要介紹了Spring遠程調用HttpClient/RestTemplate的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03Springboot整合PageOffice 實現(xiàn)word在線編輯保存功能
這篇文章主要介紹了Springboot整合PageOffice 實現(xiàn)word在線編輯保存,本文以Samples5 為示例文件結合示例代碼給大家詳細介紹,需要的朋友可以參考下2021-08-08