You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中PhpSpreadsheet实现Excel多表导入数据库可行性咨询

可行性结论

基于PhpSpreadsheet在Laravel框架下实现Excel多工作表匹配导入对应结构数据库表的需求完全可行,不存在技术障碍。

实现流程

  • 安装依赖:执行Composer命令引入PhpSpreadsheet包:composer require phpoffice/phpspreadsheet,无需额外依赖其他导入类库,直接基于原生扩展开发可控性更高。
  • 加载文件读取工作表:实例化PhpOffice\PhpSpreadsheet\IOFactory类加载上传的Excel文件,调用getAllSheets()方法即可获取文件内所有工作表实例,无需手动逐表切换。
  • 配置映射关系:提前定义关联配置数组,绑定工作表名称/索引与对应Eloquent模型、字段匹配规则,示例结构:['工作表名称' => ['model' => 对应模型类名::class, 'field_map' => [列索引 => 数据库字段名], 'header_row' => 表头所在行号]],所有匹配逻辑基于配置走,避免硬编码。
  • 逐表遍历批量入库:遍历工作表集合,跳过表头行后逐行读取单元格数据,按照配置的字段映射整理为符合数据库表结构的数组,累计到固定批次量(推荐100条)后调用Eloquent的insert()方法批量写入,降低数据库IO开销。整个导入过程必须开启数据库事务,任意一张表导入失败时整体回滚,避免产生脏数据。
  • 异常捕获:通过try-catch块捕获文件格式错误、字段不匹配、数据库写入失败等异常,返回明确的错误定位信息,例如出错的工作表名称、行号。

核心参考代码

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use PhpOffice\PhpSpreadsheet\IOFactory;
use Illuminate\Support\Facades\DB;

class ExcelImportController extends Controller
{
    /**
     * 工作表与数据库表映射配置
     */
    protected $sheetMap = [
        '用户表' => [
            'model' => \App\Models\User::class,
            'field_map' => [
                0 => 'name',
                1 => 'email',
                2 => 'phone'
            ],
            'header_row' => 1
        ],
        '订单表' => [
            'model' => \App\Models\Order::class,
            'field_map' => [
                0 => 'order_sn',
                1 => 'user_id',
                2 => 'amount',
                3 => 'pay_status'
            ],
            'header_row' => 1
        ]
    ];

    public function import(Request $request)
    {
        $request->validate([
            'file' => 'required|file|mimes:xlsx,xls'
        ]);

        $file = $request->file('file');
        $spreadsheet = IOFactory::load($file->getPathname());
        $allSheets = $spreadsheet->getAllSheets();

        DB::beginTransaction();
        try {
            foreach ($allSheets as $sheet) {
                $sheetName = $sheet->getTitle();
                // 未配置映射的工作表直接跳过
                if (!isset($this->sheetMap[$sheetName])) {
                    continue;
                }
                $config = $this->sheetMap[$sheetName];
                $highestRow = $sheet->getHighestRow();
                $insertData = [];

                // 从表头下一行开始读取数据
                for ($row = $config['header_row'] + 1; $row <= $highestRow; $row++) {
                    $rowData = $sheet->rangeToArray("A{$row}:{$sheet->getHighestColumn()}{$row}")[0];
                    $mappedRow = [];
                    foreach ($config['field_map'] as $colIndex => $dbField) {
                        $mappedRow[$dbField] = $rowData[$colIndex] ?? null;
                    }
                    // 跳过空行
                    if (!array_filter($mappedRow)) {
                        continue;
                    }
                    $mappedRow['created_at'] = now();
                    $mappedRow['updated_at'] = now();
                    $insertData[] = $mappedRow;

                    // 累计100条批量插入,降低内存与数据库压力
                    if (count($insertData) >= 100) {
                        $config['model']::insert($insertData);
                        $insertData = [];
                    }
                }
                // 写入剩余不足100条的残留数据
                if (!empty($insertData)) {
                    $config['model']::insert($insertData);
                }
            }
            DB::commit();
            return response()->json(['msg' => '所有工作表数据导入完成']);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['msg' => '导入失败:' . $e->getMessage()], 500);
        }
    }
}

优化提示

  • 单工作表数据量过万时,提前配置PhpSpreadsheet的单元格缓存策略,通过\PhpOffice\PhpSpreadsheet\Settings::setCache()方法设置缓存驱动,避免内存溢出。
  • 数据写入前增加格式校验,例如手机号格式、外键关联数据是否存在,减少写入失败概率。
  • 不要一次性将整个Excel文件内容全部加载到内存,边读边写配合批量插入可以大幅降低性能消耗。

内容的提问来源于stack exchange,提问作者Ahmad Syauqi Futtaqi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 13:24:21