今天在使用 laravel 10 的模型查询遇到一个问题?想请教下是什么原因。

$orderRefund = OrderRefund::query()
    ->where('order_no', $orderNo)
    ->where('refund_status', RefundStatusEnum::PROCESSING)
    ->first();
dump($orderRefund);exit();

上面这个查询结果打印为 null
order_no 数据库字段类型为 bigint
refund_status 数据库字段类型为 tinyint
然后使用打印出来的sql 语句去出数据库查询是能查出数据的

$orderRefundSql = OrderRefund::query()
    ->where('order_no', $orderNo)
    ->where('refund_status', RefundStatusEnum::PROCESSING)
    ->toRawSql();
dump($orderRefundSql);exit();
select * from `order_refunds` where `order_no` = '64795467258662912' and `refund_status` = 0

拿这个 sql 语句去查询是有结果集的。

但是下面这个写法又能查询出数据,就是将 $orderNo转化为int 类型

$orderRefund = OrderRefund::query()
    ->where('order_no', (int)$orderNo)
    ->where('refund_status', RefundStatusEnum::PROCESSING)
    ->first();
dump($orderRefund);exit();

就是想想知道产生这个问题的原因时什么。

$orderRefund = OrderRefund::query()
    ->where('order_no', $orderNo)
    ->first();
$orderRefund = OrderRefund::query()
    ->whereRaw("order_no = ?", [$orderNo])
    ->where('refund_status', RefundStatusEnum::PROCESSING)
    ->first();

这2中写法都是能正常查出数据的

@Rache1 的建议,
我贴一下 PHP 版本和 MySQL 版本及建表语句
laravel/framework”: “^10.10”,php 8.2.18, MySql 8.0.24,字符集 utf8mb4 排序规格utf8mb4_unicode_ci
下面建表语句,这个是无法正常查出数据的

CREATE TABLE `order_refunds` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `order_no` bigint unsigned NOT NULL COMMENT '订单号',
  `is_apply_refund` tinyint unsigned NOT NULL COMMENT '是否申请退款:1是,0否',
  `refund_amount` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '退款金额',
  `refund_status` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '退款状态:0退款中,1退款成功,2退款失败',
  `refund_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '退款原因',
  `refund_desc` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '退款说明',
  `refund_images` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '退款图片',
  `review_result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核结果',
  `review_time` datetime DEFAULT NULL COMMENT '审核时间',
  `additional_data` json DEFAULT NULL COMMENT '附加数据',
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uni_order_no` (`order_no`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单退款信息表';

下面的是能正常查出数据的,只是把refund_status变更为了有符号的整型

CREATE TABLE `order_refunds` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `order_no` bigint unsigned NOT NULL COMMENT '订单号',
  `is_apply_refund` tinyint unsigned NOT NULL COMMENT '是否申请退款:1是,0否',
  `refund_amount` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '退款金额',
  `refund_status` tinyint NOT NULL DEFAULT '0' COMMENT '退款状态:0退款中,1退款成功,2退款失败',
  `refund_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '退款原因',
  `refund_desc` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '退款说明',
  `refund_images` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '退款图片',
  `review_result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核结果',
  `review_time` datetime DEFAULT NULL COMMENT '审核时间',
  `additional_data` json DEFAULT NULL COMMENT '附加数据',
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uni_order_no` (`order_no`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单退款信息表';

不过这个问题也引起了我的注意,order_no 以后尽量使用把 varchar,以前项目基本都是varchar,所以没有遇到过此类问题, AI 有时候的建议也不是挺靠谱的,而且 bigint 类型在前端有时候显示也会有问题。但是其实 ID 大了该处理还是处理,由于 PHP 本身就是弱类型,还是需要写的时候更加规范,避免这类 BUG 的发生把。

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

给后面看的人补充一下具体原因: refund_status 字段必须要为有符号整型,我把refund_status改为无符号整型去查就会有问题。当然产生这个原因的可能也还有其他原因,这个仅供参考。但是 0 应该属于无符号整型才对。而且 order_no 转为 int 又可以查询到,总感觉哪里不太对。有大佬知道原因可以在此下面解惑一下~

3周前 评论
讨论数量: 21

Laravel Eloquent 查询时,Eloquent 会把条件参数直接绑定为字符串类型(PDO 绑定) mysql 语句查询会默认把字符串转成整型

3周前 评论
ononl (楼主) 3周前
Smilephp (作者) 3周前
ononl (楼主) 3周前
Smilephp (作者) 3周前
ononl (楼主) 3周前

两个写法生成的sql是一样的?

3周前 评论
ononl (楼主) 3周前

推荐个插件 clockwork

file

3周前 评论
ononl (楼主) 3周前

你是不是开了laravel查询的严格模式啊。看下config/databases.php,mysql配置里面strict是不是配置了true

3周前 评论
ononl (楼主) 3周前

order_no 类型改为varchar吧。
no太长,orm判定为字符了
要么用whereRaw设置no条件

3周前 评论
ononl (楼主) 3周前

作为新手来说我也碰到过这种问题,目前就是和你的方法一行手动强制转换类型

3周前 评论
ononl (楼主) 3周前
sunny123456 (作者) 3周前

奇了怪了,我数据库把索引重新改回来又正常了?不管了,现在这段代码能正常运行了。

$orderRefund = OrderRefund::query()
    ->where('order_no', $orderNo)
    ->where('refund_status', RefundStatusEnum::PROCESSING)
    ->first();

至今没找到原因是什么。就改了下索引,又改回来就可以查出来了

3周前 评论

给后面看的人补充一下具体原因: refund_status 字段必须要为有符号整型,我把refund_status改为无符号整型去查就会有问题。当然产生这个原因的可能也还有其他原因,这个仅供参考。但是 0 应该属于无符号整型才对。而且 order_no 转为 int 又可以查询到,总感觉哪里不太对。有大佬知道原因可以在此下面解惑一下~

3周前 评论

你这样干说,只有神知道。

不如把能复现的环境信息、PHP、MySQL、Laravel 的版本以及数据库的建表语句提供一下,好让其他人能复现

2周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!