您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“怎么使用springboot+mybatis快速插入大量數(shù)據(jù)”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“怎么使用springboot+mybatis快速插入大量數(shù)據(jù)”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。
用一個(gè) for 循環(huán),把數(shù)據(jù)一條一條地插入;生成一條插入 sql,類(lèi)似這種 insert into user(name,pwd) values('aa','123'),('cc','123')...
該方案的優(yōu)勢(shì)在于,JDBC 中的 PreparedStatement 有預(yù)編譯功能,預(yù)編譯之后會(huì)緩存起來(lái)。之后SQL執(zhí)行會(huì)比較快,且 JDBC可以開(kāi)啟批處理,這個(gè)批處理執(zhí)行非常給力。
劣勢(shì)在于,很多時(shí)候我們的 SQL 服務(wù)器和應(yīng)用服務(wù)器可能并不是同一臺(tái),所以必須要考慮網(wǎng)絡(luò) IO。如果網(wǎng)絡(luò) IO 比較費(fèi)時(shí)間的話(huà),那么可能會(huì)拖慢 SQL 執(zhí)行的速度。
該方案的優(yōu)勢(shì)在于,只有一次網(wǎng)絡(luò) IO。即使分片處理也只是數(shù)次網(wǎng)絡(luò) IO,所以這種方案不會(huì)在網(wǎng)絡(luò) IO 上花費(fèi)太多時(shí)間。
當(dāng)然這種方案也有劣勢(shì)。一是 SQL 太長(zhǎng)了,甚至可能需要分片后批量處理;二是無(wú)法充分發(fā)揮 PreparedStatement 預(yù)編譯的優(yōu)勢(shì),SQL 要重新解析且無(wú)法復(fù)用;三是最終生成的 SQL 太長(zhǎng)了,數(shù)據(jù)庫(kù)管理器解析這么長(zhǎng)的 SQL 也需要時(shí)間。
我們接下來(lái)會(huì)采用第二種方案進(jìn)行實(shí)現(xiàn)。
如果我們想要拉高插入效率,肯定不能夠一條一條地插入了,必須得使用foreach批量插入;
采用多線程進(jìn)行異步插入,提升性能;
我們不可能單次提交多個(gè)insert,大量的插入操作會(huì)很耗時(shí),短時(shí)間內(nèi)完不成,可以采用定時(shí)任務(wù)來(lái)實(shí)現(xiàn)。
接下來(lái)我們就來(lái)說(shuō)說(shuō)具體該怎么利用代碼進(jìn)行實(shí)現(xiàn)。
本案例主要是基于SpringBoot整合mybatis進(jìn)行實(shí)現(xiàn)。
<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>
@SpringBootApplication //引導(dǎo)類(lèi)核心注解 @EnableScheduling //開(kāi)啟定時(shí)任務(wù) public class BatchApplication { public static void main(String[] args) { SpringApplication.run(BatchApplication.class,args); } }
server: port: 9999 # 指定端口號(hào) 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 # 別名
創(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效率會(huì)比INNODB快。
User.java
@Data public class User { private int id; private String username; private String pwd; private int sex; private LocalDate birthday; }
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>
SpringBoot默認(rèn)整合了scheduled,使用步驟如下:
在引導(dǎo)類(lèi)加入@EnableScheduling注解,開(kāi)啟定時(shí)任務(wù);
在業(yè)務(wù)層方法上加入 @Scheduled注解,定義cron表達(dá)式周期執(zhí)行。
業(yè)務(wù)層方法中開(kāi)啟的線程可以根據(jù)當(dāng)前機(jī)器的配置來(lái)修改。我們這里開(kāi)了7個(gè)線程,每個(gè)線程去執(zhí)行20次循環(huán),一次添加5000條數(shù)據(jù)。這里要注意mybatis批量插入時(shí),不建議超過(guò)10000條錯(cuò)誤。因?yàn)閿?shù)據(jù)量過(guò)大,容易出現(xiàn)棧內(nèi)存溢出的問(wè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("定時(shí)器被觸發(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()); } } } }
我們用來(lái)模擬生成要插入的數(shù)據(jù),實(shí)際業(yè)務(wù)開(kāi)發(fā)的時(shí)候可以是從excel中導(dǎo)入的數(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; } }
線程池參數(shù):
corePoolSize 核心線程數(shù),在線程池中要保證的最小線程數(shù);
mainumPoolSize 最大線程數(shù),線程池中能運(yùn)行的最大線程數(shù);
keepAliveTime 保證存活時(shí)間,當(dāng)線程空閑時(shí)間,多久會(huì)回收線程;
unit 和keepAliveTime配合使用,時(shí)間單位;
workQueue 工作隊(duì)列,用于存儲(chǔ)任務(wù)在任務(wù)被執(zhí)行之前。
@Configuration public class ThreadPoolExecutorConfig { @Bean public ThreadPoolExecutor threadPoolExecutor() { //線程池中6個(gè)線程,最大8個(gè)線程,用于緩存任務(wù)的阻塞隊(duì)列數(shù)5個(gè) ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 8, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100)); executor.allowCoreThreadTimeOut(true);//允許超時(shí) return executor; } }
讀到這里,這篇“怎么使用springboot+mybatis快速插入大量數(shù)據(jù)”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。