目录
- 概述
- 准备工作
- 创建数据库表
- 创建Java实体类
- 创建MyBatis映射文件和DAO接口
- 编写Java代码实现多张表大批量插入的功能
- 总结
1. 概述
在实际的开发中,我们经常需要将大量的数据插入到数据库中。如果使用单条插入的方式,会导致数据库连接频繁的开启和关闭,从而导致程序性能低下。为了提高程序的性能,我们可以使用批处理的方式来插入数据。同时,我们还可以使用Java编程式事务、多线程、线程池、List分页等技术来实现多张表大批量插入的功能。
本文将介绍如何使用Java编程式事务、多线程、线程池、List分页等技术实现多张表大批量插入的功能。
2. 准备工作
在开始之前,我们需要准备好以下工具和环境:
- JDK 1.8或以上版本
- Maven 3.0或以上版本
- MySQL 5.7或以上版本
- MyBatis 3.5.7或以上版本
3. 创建数据库表
我们首先需要创建数据库表,以便在后续的实现中使用。假设我们需要向以下两张表中插入数据:
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(50) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `order` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) DEFAULT NULL,`product_name` varchar(50) DEFAULT NULL,`price` decimal(10,2) DEFAULT NULL,PRIMARY KEY (`id`),KEY `user_id` (`user_id`),CONSTRAINT `order_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4. 创建Java实体类
我们需要创建Java实体类,以便在后续的实现中使用。假设我们需要向以上两张表中插入数据,我们可以创建以下两个Java实体类:
public class User {private Integer id;private String name;private Integer age;// 省略getter和setter方法
}public class Order {private Integer id;private Integer userId;private String productName;private BigDecimal price;// 省略getter和setter方法
}
5. 创建MyBatis映射文件和DAO接口
我们需要创建MyBatis映射文件和DAO接口,以便在后续的实现中使用。假设我们需要向以上两张表中插入数据,我们可以创建以下两个MyBatis映射文件:
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.example.mapper.UserMapper"><insert id="insertBatch" parameterType="java.util.List">INSERT INTO `user` (`name`, `age`)VALUES<foreach collection="list" item="item" index="index" separator=",">(#{item.name}, #{item.age})</foreach></insert>
</mapper>
OrderMapper.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.example.mapper.OrderMapper"><insert id="insertBatch" parameterType="java.util.List">INSERT INTO `order` (`user_id`, `product_name`, `price`)VALUES<foreach collection="list" item="item" index="index" separator=",">(#{item.userId}, #{item.productName}, #{item.price})</foreach></insert>
</mapper>
然后我们需要创建对应的DAO接口:
public interface UserMapper {void insertBatch(List<User> userList);
}public interface OrderMapper {void insertBatch(List<Order> orderList);
}
6. 编写Java代码实现多张表大批量插入的功能
我们可以使用Java编程式事务、多线程、线程池、List分页等技术来实现多张表大批量插入的功能。具体实现步骤如下:
- 将数据按照每页大小分割成多个List;
- 使用线程池和CompletableFuture异步处理每个List;
- 在每个线程中开启事务,将数据批量插入到数据库中;
- 如果有任何一个线程的事务失败,回滚所有线程的事务。
以下是示例代码:
@Service
public class BatchInsertService {private static final int PAGE_SIZE = 1000;private final UserMapper userMapper;private final OrderMapper orderMapper;private final ThreadPoolTaskExecutor executor;public BatchInsertService(UserMapper userMapper, OrderMapper orderMapper, ThreadPoolTaskExecutor executor) {this.userMapper = userMapper;this.orderMapper = orderMapper;this.executor = executor;}public void batchInsert(List<User> userList, List<Order> orderList) {List<List<User>> userPages = splitList(userList, PAGE_SIZE);List<List<Order>> orderPages = splitList(orderList, PAGE_SIZE);List<CompletableFuture<Void>> futures = new ArrayList<>();for (int i = 0; i < userPages.size(); i++) {List<User> page = userPages.get(i);int index = i;CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {try {TransactionTemplate transactionTemplate = new TransactionTemplate();transactionTemplate.executeWithoutResult(status -> {userMapper.insertBatch(page);});} catch (Exception e) {throw new RuntimeException("Failed to insert users in page " + index, e);}}, executor);futures.add(future);}for (int i = 0; i < orderPages.size(); i++) {List<Order> page = orderPages.get(i);int index = i;CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {try {TransactionTemplate transactionTemplate = new TransactionTemplate();transactionTemplate.executeWithoutResult(status -> {orderMapper.insertBatch(page);});} catch (Exception e) {throw new RuntimeException("Failed to insert orders in page " + index, e);}}, executor);futures.add(future);}CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();}private <T> List<List<T>> splitList(List<T> list, int pageSize) {List<List<T>> pages = new ArrayList<>();int size = list.size();int pageCount = (size + pageSize - 1) / pageSize;for (int i = 0; i < pageCount; i++) {int fromIndex = i * pageSize;int toIndex = Math.min((i + 1) * pageSize, size);List<T> page = list.subList(fromIndex, toIndex);pages.add(page);}return pages;}
}
在上面的代码中,我们首先将数据按照每页大小分割成多个List,然后使用线程池和CompletableFuture异步处理每个List。在每个线程中,我们使用TransactionTemplate来开启事务,将数据批量插入到数据库中。如果有任何一个线程的事务失败,我们会回滚所有线程的事务。
7. 总结
本文介绍了如何使用Java编程式事务、多线程、线程池、List分页等技术实现多张表大批量插入的功能。具体实现步骤包括创建数据库表、Java实体类、MyBatis映射文件和DAO接口,以及编写Java代码实现多张表大批量插入的功能。通过使用这些技术,我们可以提高程序的性能,减少数据库连接池的压力。在实现过程中,我们还介绍了如何使用编程式事务来保证数据的一致性,以及如何使用线程池和分页技术来提高程序的效率。