多线程池多线程导入Excel数据到数据库,使用Apache POI把数据库数据导出为Excel文件

1.读取Excel数据并存储在内存中

@Component
public class ExcelReader {

    @Autowired
    private UserService userService;

    public List<User> readExcel(String filePath) throws IOException {
        FileInputStream inputStream = new FileInputStream(new File(filePath));
        Workbook workbook = new XSSFWorkbook(inputStream);
        Sheet sheet = workbook.getSheetAt(0);

        List<User> userList = new ArrayList<>();
        for (Row row : sheet) {
            if (row.getRowNum() == 0) {
                continue; // 跳过表头
            }
            String name = row.getCell(0).getStringCellValue();
            int age = (int) row.getCell(1).getNumericCellValue();
            String address = row.getCell(2).getStringCellValue();
            User user = new User(name, age, address);
            userList.add(user);
        }
        return userList;
    }
}

我们使用Apache POI库来读取Excel文件,并将其转换为User对象列表。每行数据都按照指定的单元格格式进行解析,并用User对象表示。注意,此方法可以在多个线程之间共享调用,因为它只是读取内存中的数据,不涉及外部状态。

2.保存Excel数据到数据库中

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public void saveUsers(List<User> users) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        int batchSize = 100; // 每个线程池处理100条记录
        for (int i = 0; i < users.size(); i += batchSize) {
            final List<User> batchList = users.subList(i, Math.min(i + batchSize, users.size()));
            executorService.submit(() -> {
                try {
                    for (User user : batchList) {
                        userRepository.save(user);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
    }

}

我们使用Java Executor框架创建了5个大小为100的线程池,并将Excel数据分成100条记录的批次。然后,我们将每个批次提交给一个线程池并异步处理它们。

注意,虽然每个线程池有100个线程,但实际上只有一小部分线程会在任何给定时间运行(具体取决于系统资源和线程调度算法)。这种设计可以提高系统的吞吐量,同时避免过多的线程竞争和内存占用。

    

3.导出数据库数据到Excel文件

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public void exportUsersToExcel(String filePath) throws IOException {
        List<User> users = userRepository.findAll();
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Users");

        // 创建表头
        Row header = sheet.createRow(0);
        header.createCell(0).setCellValue("ID");
        header.createCell(1).setCellValue("Name");
        header.createCell(2).setCellValue("Age");
        header.createCell(3).setCellValue("Address");

        // 填充数据
        int rowIndex = 1;
        for (User user : users) {
            Row row = sheet.createRow(rowIndex++);
            row.createCell(0).setCellValue(user.getId());
            row.createCell(1).setCellValue(user.getName());
            row.createCell(2).setCellValue(user.getAge());
            row.createCell(3).setCellValue(user.getAddress());
        }

        FileOutputStream outputStream = new FileOutputStream(new File(filePath));
        workbook.write(outputStream);
        outputStream.close();
    }

}

我们使用Apache POI库来创建一个新的Excel工作簿,并将User对象列表写入其中。我们首先创建一个名为“Users”的工作表,并在第一行添加表头。然后,我们迭代用户列表并在工作表中创建一个新行。最后,我们将工作簿写入指定的输出流中,并关闭文件。

通过组合这些方法,我们可以创建一个允许多个线程同时读取、处理和写入Excel数据的应用程序。使用Apache POI库可以方便地操作Excel数据,并且使用Java Executor框架可以轻松实现并发处理。

使用多线程池进行数据上传可以提高并发处理能力和效率,但也存在一些缺点,包括:

  1. 内存占用:每个线程都需要分配一定的内存空间,当同时运行大量线程时,会消耗大量的内存资源。这可能导致系统性能下降或甚至出现内存不足的情况。

  2. 上下文切换开销:在多线程环境下,操作系统需要频繁地在不同的线程之间进行切换。这种上下文切换会引入一定的开销,特别是当线程数目很多时,上下文切换的开销可能会超过线程并发带来的性能提升。

  3. 线程安全问题:多线程并发操作共享的数据时,需要考虑线程安全性。如果不正确地处理共享数据的访问控制,可能会导致数据不一致或竞争条件等问题,进而引发程序错误或异常。

  4. 调试和维护复杂性:多线程编程相对于单线程编程更加复杂,涉及到线程间通信、同步、锁等概念和机制。调试多线程程序可能会更加困难,并且由于线程之间的相互依赖关系,修改一个线程可能会对其他线程产生影响,增加了维护的复杂性。

  5. 资源限制:多线程并发上传可能会对网络带宽、磁盘IO等资源造成较大压力。当同时上传大量数据时,可能会导致资源竞争和拥塞,影响整体性能。

尽管多线程池可以提高数据上传的效率,但在使用时需要权衡以上缺点,根据具体情况进行合理的调度和控制,以确保系统的稳定性和性能。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值