
本文详解 Laravel 中 DB 查询构建器 update() 方法因重复绑定事件导致单 ID 更新却修改多行的问题,提供基于 Eloquent 的安全替代方案及完整调试指南。
本文详解 laravel 中 db 查询构建器 `update()` 方法因重复绑定事件导致单 id 更新却修改多行的问题,提供基于 eloquent 的安全替代方案及完整调试指南。
在 Laravel 开发中,使用 DB::table()->where('id', $id)->update(...) 本应精准更新单条记录,但实际却更新了两行——这通常并非 SQL 逻辑错误,而是前端事件绑定重复引发的“伪多行更新”。从您提供的完整 Blade 模板和 JS 代码可定位根本原因:$('#tolak').on('click', ...) 事件监听器被多次注册。
? 问题根源分析
观察您的 JavaScript 代码,$('#tolak').on('click', ...) 出现在两个位置:
- 第一处在 <script> 标签内 $(document).ready(...) 的末尾;</script>
- 第二处(隐含)在 callData(e) 函数中:每次打开模态框时,都会动态设置 $('#tolak').attr('data-id', ...),但未解绑旧事件,导致每次点击触发多个相同 AJAX 请求。
这意味着:当用户点击“Tolak”按钮时,可能同时发出 2 次(甚至更多)完全相同的 POST 请求,均携带相同 id,从而造成数据库被更新两次——日志中看似“一行更新两次”,实为并发请求叠加效果。
✅ 正确修复方案:避免事件重复绑定 + 使用 Eloquent 增强健壮性
1. 修正前端:确保事件仅绑定一次
将 $('#tolak').on('click', ...) 移出 $(document).ready() 的重复执行域,改用事件委托(Event Delegation),避免因 DOM 动态插入导致重复绑定:
// ✅ 推荐:使用事件委托,绑定到静态父容器(如 body 或 document)
$(document).on('click', '#tolak', function() {
const id = $(this).data('id'); // 推荐用 .data() 替代 .attr()
const name = $(this).data('name');
Swal.fire({
title: 'Konfirmasi',
text: `Apakah anda yakin akan menolak form pendaftaran driver ${name}`,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ya, tolak!',
cancelButtonText: 'Batal',
}).then((result) => {
if (result.isConfirmed) {
Swal.showLoading();
$.ajax({
url: '{{ route('admin.verifDriver') }}',
type: 'POST', // 注意:type 应为 'POST',不是 'ajax'
data: {
_token: '{{ csrf_token() }}', // ⚠️ 必须添加 CSRF Token
id: id,
status: 2,
},
success: function(data) {
Swal.fire('Sukses!', `Berhasil tolak pendaftaran ${name}`, 'success');
fetchData();
},
error: function(xhr) {
console.error('Update gagal:', xhr.responseJSON?.message || xhr.statusText);
Swal.fire('Gagal', 'Terjadi kesalahan saat memproses permintaan.', 'error');
},
complete: function() {
Swal.hideLoading();
}
});
}
});
});? 提示:type: 'ajax' 是无效配置,jQuery 中应使用 type: 'POST';同时务必添加 _token 字段防止 CSRF 验证失败。
2. 后端优化:优先使用 Eloquent Model(更安全、可审计)
虽然原 DB::table(...)->where(...)->update() 语法本身无错,但改用 Eloquent 可带来三重优势:
- 自动处理模型事件(如 updating/updated);
- 支持批量赋值保护($fillable);
- 便于后续扩展(如日志、通知、事务)。
// ✅ 推荐控制器写法(需确保 Driver 模型存在且正确配置)
use App\Models\Driver;
public function verif(Request $request)
{
// 验证输入(强烈建议)
$validated = $request->validate([
'id' => 'required|exists:drivers,id',
'status' => 'required|in:0,1,2', // 假设 0=Pending, 1=Approved, 2=Rejected
]);
$driver = Driver::findOrFail($validated['id']);
$driver->status = $validated['status'];
$driver->save();
return response()->json(['message' => 'Status berhasil diperbarui']);
}对应 Driver 模型示例:
// app/Models/Driver.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Driver extends Model
{
protected $fillable = ['status']; // 显式允许 mass assignment
}3. 额外加固措施(生产环境必备)
- 添加数据库唯一索引:确认 drivers.id 是主键(自动唯一),避免底层数据异常;
-
启用查询日志临时调试:
\DB::enableQueryLog(); // ... your update code ... dd(\DB::getQueryLog()); // 查看实际执行的 SQL 是否符合预期
-
服务端幂等性兜底(进阶):对状态变更类操作,可增加条件更新:
Driver::where('id', $id) ->where('status', 0) // 仅当原状态为“待审核”时才更新 ->update(['status' => $status]);
? 总结
| 问题类型 | 根本原因 | 解决要点 |
|---|---|---|
| 表象 | 单 ID 更新影响两行 | 实际是多次 AJAX 请求并发执行 |
| 前端 | $('#tolak').on() 被重复绑定 | 改用 $(document).on('click', selector, ...) 事件委托 |
| 后端 | 原生 DB 查询缺乏验证与扩展性 | 迁移至 Eloquent Model,添加请求验证与异常处理 |
| 安全 | 缺少 CSRF Token 和输入校验 | 补全 _token,使用 validate() 强制约束参数 |
遵循以上方案,不仅能彻底解决“更新两行”的问题,更能提升代码可维护性与系统健壮性。记住:Laravel 的优雅,始于对约定与最佳实践的坚持。


















