目录
- 概述
- 准备工作
- 创建数据库表
- 创建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代码实现多张表大批量插入的功能。通过使用这些技术,我们可以提高程序的性能,减少数据库连接池的压力。在实现过程中,我们还介绍了如何使用编程式事务来保证数据的一致性,以及如何使用线程池和分页技术来提高程序的效率。