Laravel外部数据导入怎么处理

wen PHP项目 1

本文目录导读:

Laravel外部数据导入怎么处理

  1. 数据获取方式
  2. 数据清洗与验证
  3. 批量插入与更新
  4. 队列处理(推荐大量数据)
  5. 完整示例:CSV导入控制器
  6. 推荐包

在 Laravel 中处理外部数据导入,通常需要解决数据获取数据清洗批量存储错误处理这几个核心问题,以下是几种常见的处理方案和最佳实践。

数据获取方式

从文件导入(CSV/Excel)

use Illuminate\Support\Facades\Storage;
use League\Csv\Reader;
// 从上传文件读取CSV
$file = request()->file('import_file');
$csv = Reader::createFromPath($file->getPathname(), 'r');
$csv->setHeaderOffset(0); // 第一行为表头
foreach ($csv as $record) {
    // $record 是关联数组
    $data[] = [
        'name' => $record['Name'],
        'email' => $record['Email'],
        'created_at' => now(),
        'updated_at' => now(),
    ];
}

从API获取

use Illuminate\Support\Facades\Http;
$response = Http::timeout(30)->retry(3, 100)->get('https://api.example.com/data');
$records = $response->json();

从数据库连接

// 在config/database.php配置外部数据库连接
$users = DB::connection('external_db')
    ->table('users')
    ->where('updated_at', '>', $lastSync)
    ->get();

数据清洗与验证

使用 Laravel Validation

use Illuminate\Support\Facades\Validator;
$rules = [
    '*.name' => 'required|string|max:255',
    '*.email' => 'required|email|unique:users,email',
    '*.age' => 'nullable|integer|min:0|max:150',
];
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
    // 收集错误信息
    $errors = $validator->errors()->all();
    Log::warning('Import validation failed', ['errors' => $errors]);
    return back()->withErrors($validator);
}

数据转换与清洗

$cleanData = collect($rawData)->map(function ($item) {
    return [
        'name' => trim($item['name'] ?? ''),
        'email' => strtolower(trim($item['email'] ?? '')),
        'amount' => (float) str_replace(['$', ','], '', $item['amount']),
        'status' => in_array($item['status'], ['active', 'inactive']) ? $item['status'] : 'unknown',
    ];
});

批量插入与更新

批量插入(性能最优)

// 每次插入1000条
$chunks = array_chunk($cleanData, 1000);
foreach ($chunks as $chunk) {
    User::insert($chunk);
}

UPSERT(存在则更新,不存在则插入)

use Illuminate\Support\Facades\DB;
// 基于email字段判断重复
DB::table('users')->upsert(
    $cleanData,
    ['email'], // 唯一键
    ['name', 'phone', 'updated_at'] // 需要更新的字段
);

使用 firstOrCreate / updateOrCreate

foreach ($cleanData as $data) {
    User::updateOrCreate(
        ['email' => $data['email']],
        $data
    );
}

队列处理(推荐大量数据)

创建 Job

// app/Jobs/ImportUsersJob.php
class ImportUsersJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    protected $chunk;
    public function __construct(array $chunk)
    {
        $this->chunk = $chunk;
    }
    public function handle()
    {
        DB::transaction(function () {
            foreach ($this->chunk as $row) {
                User::create($row);
            }
        });
    }
    public function failed(\Throwable $exception)
    {
        Log::error('Import chunk failed', [
            'error' => $exception->getMessage(),
            'chunk' => $this->chunk
        ]);
    }
}
// 使用
$chunks = array_chunk($cleanData, 500);
foreach ($chunks as $chunk) {
    ImportUsersJob::dispatch($chunk);
}

完整示例:CSV导入控制器

<?php
namespace App\Http\Controllers;
use App\Jobs\ImportUsersJob;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use League\Csv\Reader;
class ImportController extends Controller
{
    public function importUsers(Request $request)
    {
        // 1. 验证上传文件
        $request->validate([
            'file' => 'required|file|mimes:csv,txt|max:10240',
        ]);
        try {
            // 2. 读取CSV
            $csv = Reader::createFromPath($request->file('file')->getPathname(), 'r');
            $csv->setHeaderOffset(0);
            $records = [];
            $errors = [];
            $rowNumber = 0;
            // 3. 逐行处理
            foreach ($csv as $row) {
                $rowNumber++;
                // 验证单行数据
                $validator = Validator::make($row, [
                    'name' => 'required|string|max:255',
                    'email' => 'required|email',
                ]);
                if ($validator->fails()) {
                    $errors[] = "Row {$rowNumber}: " . implode(', ', $validator->errors()->all());
                    continue;
                }
                $records[] = [
                    'name' => trim($row['name']),
                    'email' => strtolower(trim($row['email'])),
                    'phone' => $row['phone'] ?? null,
                    'created_at' => now(),
                    'updated_at' => now(),
                ];
            }
            // 4. 批量导入(使用队列或直接插入)
            if (!empty($records)) {
                $chunks = array_chunk($records, 500);
                foreach ($chunks as $chunk) {
                    ImportUsersJob::dispatch($chunk);
                }
            }
            // 5. 返回结果
            return response()->json([
                'success' => true,
                'imported' => count($records),
                'errors' => $errors,
                'message' => count($records) . ' records queued for import'
            ]);
        } catch (\Exception $e) {
            Log::error('Import failed: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Import failed: ' . $e->getMessage()
            ], 500);
        }
    }
}

推荐包

  • Maatwebsite/Laravel-Excel:强大的Excel/CSV处理,支持导入、导出、批量验证
  • Laravel-Excel 导入示例
    use Maatwebsite\Excel\Facades\Excel;
    use App\Imports\UsersImport;

Excel::import(new UsersImport, $request->file('file'));


## 7. 关键注意事项
1. **内存管理**:大文件使用`lazyCollection()`或队列分块处理
2. **事务处理**:每块数据使用独立事务,避免全部回滚
3. **错误处理**:记录错误行,允许部分导入成功
4. **唯一约束**:使用`upsert`或先查询后插入
5. **性能监控**:记录导入时间、数量、失败原因
6. **用户反馈**:提供进度条或异步通知
## 
| 场景 | 推荐方案 |
|------|----------|
| 小数据量 (<1000) | 直接同步插入 + 验证 |
| 中等数据量 (1000-10000) | 批量chunk插入 + 事务 |
| 大数据量 (>10000) | 队列分片处理 + 事务 |
| 需要更新已有数据 | `upsert` 或 `updateOrCreate` |
| 复杂格式(Excel) | Maatwebsite/Laravel-Excel |
选择方案时,根据数据量大小、实时性要求和错误容忍度来决定是同步处理还是异步队列处理。

抱歉,评论功能暂时关闭!