
laravel 项目中,当将带小数的数值(如 20.10)存入数据库 quantity 字段时出现自动舍入(变成 20),根本原因在于数据库字段类型定义不当或模型/框架未正确处理浮点精度,需结合数据库结构、数据传递与 laravel 类型转换三方面统一修复。
laravel 项目中,当将带小数的数值(如 20.10)存入数据库 quantity 字段时出现自动舍入(变成 20),根本原因在于数据库字段类型定义不当或模型/框架未正确处理浮点精度,需结合数据库结构、数据传递与 laravel 类型转换三方面统一修复。
在 Laravel(或基于 CodeIgniter 的自定义框架,如本例所示)中遇到 quantity 字段数值被意外舍入(例如输入 20.10 却存为 20),通常并非 Laravel 本身“主动四舍五入”,而是由以下任一或多个环节导致:
✅ 1. 数据库字段类型必须精确匹配业务需求
VARCHAR 或 INT / TINYINT 等整型字段绝对不可用于存储带小数的数量值。即使你已改为 DECIMAL,若定义不恰当仍会截断:
-- ❌ 错误:DECIMAL(10,0) → 小数位为 0,所有小数部分被丢弃 -- ✅ 正确:根据业务场景预留足够精度,例如: ALTER TABLE `pur_order_detail` MODIFY COLUMN `quantity` DECIMAL(12,4) NOT NULL DEFAULT '0.0000';
-
DECIMAL(12,4)表示最多 12 位数字,其中 4 位为小数(支持如99999999.9999); - 若业务中 quantity 最大为 9999.99,推荐
DECIMAL(8,2);若需更高精度(如化工/医药计量),用DECIMAL(12,4)更稳妥。
⚠️ 注意:执行
ALTER TABLE后务必清空缓存并验证表结构(DESCRIBE pur_order_detail),避免因旧结构残留导致无效修改。
✅ 2. 确保传入数据未被隐式类型转换
检查 $data['quantity'] 在进入 insert_batch() 前是否已被 PHP 强制转为整数或浮点数丢失精度:
// 在 foreach 循环中添加调试日志(开发环境)
foreach($rq_val as $key => $rq){
\Log::info('Raw quantity before insert', ['raw' => $rq['quantity'], 'type' => gettype($rq['quantity'])]);
if($rq['item_code'] != ''){
array_push($es_detail, $rq_val[$key]);
}
}常见陷阱:
- 使用
(int)强转或intval()—— 直接丢弃小数; -
floatval()在某些 PHP 版本或精度设置下可能产生20.099999999999998,再经round()或数据库隐式转换后变为20; -
正确做法:保持字符串原始格式传入,或使用
number_format($val, 4, '.', '')标准化小数位。
✅ 3. 验证框架层是否启用自动类型转换(Laravel 特有)
虽然本例使用的是 CodeIgniter 风格 DB 操作,但若后续迁移到 Laravel Eloquent,务必在 Model 中显式声明 $casts:
// app/Models/PurOrderDetail.php
protected $casts = [
'quantity' => 'decimal:4',
'unit_price' => 'decimal:4',
'total_money' => 'decimal:2',
];该配置确保 Eloquent 自动将数据库读取的 DECIMAL 值作为高精度 string 或 float 处理,并在写入前按指定精度格式化,避免 PHP 浮点误差。
✅ 4. 补充建议:批量插入前做数据校验
在 insert_batch() 前统一规范化小数位,提升健壮性:
foreach($es_detail as &$detail) {
// 强制保留 4 位小数,避免前端传入 '20.1' 或 '20.10000' 导致不一致
$detail['quantity'] = number_format((float)$detail['quantity'], 4, '.', '');
$detail['unit_price'] = number_format((float)$detail['unit_price'], 4, '.', '');
$detail['total_money'] = number_format((float)$detail['total_money'], 2, '.', '');
}? 总结
解决 quantity 被舍入的核心路径是:
? 数据库层:使用 DECIMAL(M,N) 替代 VARCHAR/INT,且 N ≥ 2(推荐 N=4);
? 应用层:避免任何 intval()/(int) 操作,优先以字符串或标准化 number_format 传递;
? 框架层(Laravel):通过 $casts 显式声明 decimal 类型及精度;
? 验证层:在入库前打印/日志原始值,确认问题发生在哪一环。
完成上述调整后,20.10 将原样存入数据库并准确返回,彻底规避“神秘舍入”问题。


















