猿问

使用Eloquent orm关于PHP传参类型和mysql字段类型不一致,导致不走索引, 一些思考?希望有人解惑

问题描述

典型的手机号问题,数据库varchar, 手机号加了索引,但是php传参传int
public function getByPhone($phone){

return $this->userFollow
    ->where('phone', $phone)
    ->get();

}
$this->getByPhone(13845678889); //不走索引
打印出的原生sql是:
string(48) "select * from zp_user_follow where phone = ?" array(1) { [0]=> int(15000475201) }

$this->getByPhone('13845678889'); //走索引
打印出的原生sql是:
string(48) "select * from zp_user_follow where phone = ?" array(1) { [0]=> string(11) "15000475201" }

问题出现的环境背景及自己尝试过哪些方法

在变量前面加入类型
public function getByPhone(string $phone){

return $this->userFollow
    ->where('phone', $phone)
    ->get();

}
这是方式是强制约束,但是程序员如果不写呢?如果传的是个数组,数组里是['phone' => 13845678889];怎么解决?

相关代码

laravel 底层是pdo,pdo绑定参数的底层代码,是会判断第三个参数使用的类型
public function bindValues($statement, $bindings)
{

foreach ($bindings as $key => $value) {
    $statement->bindValue(
        is_string($key) ? $key : $key + 1, $value,
        is_int($value) || is_float($value) ? PDO::PARAM_INT : PDO::PARAM_STR
    );
}

}

你期待的结果是什么?实际看到的错误信息又是什么?

有没有办法,在不改底层laravel,就算程序员写错了,可以在查询的时候,自动解析查询参数的类型和数据库字段类型进行匹配,也能正确保证走索引,如果没有办法,只能把问题抛给程序员?让他们注意写代码的时候,声明查询参数的类型要和数据库一致?如果他们忘记了怎么办?问题在放大一点,假如生成环境数据量大,不走索引,全表扫描,如果因为这个问题,导致了慢sql,生成环境出bug, 扣绩效?批评?

是把问题抛给人本身,如果抛给人本身,那么是我们习惯约定大于配置,给自己找个不想用技术手段解决的理由?还是可以用技术手段解决,就得改底层了,但是laravel底层为什么这么实现呢?它本身就把问题抛给我们开发者,需要我们执行约定?,希望有人解惑啊!!!

LEATH
浏览 397回答 3
3回答

红颜莎娜

服务层对参数进行类型转换的处理

收到一只叮咚

这个和laravel没有关系。 数据库里的phone字段是varchar型,但是你查询的数据是int型,这里导致了mysql隐式类型转换,所以你的索引失效。 在设计表的时候就需要考虑好这些问题,实现的过程做好类型约束

手掌心

对!这就是程序员要处理的事情。这种用法是PDO的方式,与laravel无关。mysql的类型是开发者定义的,所以该使用什么类型,也由开发者决定这是不是框架层和语言层要解决的事情,即使裸写sql,一样会有人写错。 换个角度,这其实是sql的使用知识,只不过通过中间层控制sql,有不同的使用规则,这是需要使用者掌握的
随时随地看视频慕课网APP
我要回答