团队规定要开始禁用 ORM

公司的多位上司定了下面一条开发规范军则,小弟资质不深,只是看不太懂给的理由,还请大佬们评论一番,给些指导。

禁止使用 ORM 自动生成的 SQL 语句,请将 SQL 直接写在代码里。参数可以使用绑定参数的 API 。比如 ActiveRecord 提供的 update()/insert() 方法,均不可使用。每一个数据库操作应有显式的 SQL 声明。

理由:

维护占生命周期的90% 。

在整个开发和维护过程中,我们一直在干这几件事:
检索:找到它。
追溯:它从哪里来。
跟踪:它到哪里去。

于是:

  1. 对象必须能够被定位。越精确(比如消除重复项)越好、越容易被记忆越好。
  2. 强线索。比如显式声明的字段 obj.MyField ,通过 IDE 可以看到它的定义(含注释)、它被多少地方使用到、可以自动重构重命名;而 obj[“MyField”] 只能字符串全文检索了。如果有多个不同地方都叫 MyField ,还得消除歧义(第一点)。
  3. 原生态。信息传递过程中尽量不发生改变,越静态和固定越容易被跟踪。反之,如果一开始叫 A,传递到第二处叫 B,第三处叫 C ,整个线索可能就乱了。
    …(还有好多)

目前 PHP 上的 ORM 如 ActiveRecord 基于约定的表名、动态生成的 SQL 不能满足上述要求。
使用动态生成的SQL,省下来的是第一次开发的时间。在后续的维护过程中则制造负效益。

然后:

  1. SQL 复制下来就可以贴到数据库工具里跑了,调试、调优都需要。动态生成的,拿到原始语句很困难。
  2. 动态的语句不是最优的。隐藏了细节,最终性能调优上可能会产生问题。

另外说明下,写下这个理由的 leader 原先主要做的是 .net 开发。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 100

叫你领导不要用框架.

2年前 评论
一念沧海一念桑田 1年前
playmaker

难道为了调试 就不能装个 Clockwork
这种不香吗?

Laravel

2年前 评论
晏南风 2年前

ORM的出现本来就是为了规范开发和安全,Eloquent 内部使用的是 PDO 参数绑定,所以大部分的请求是安全的。
你所说的90%的时间在找关于模型的一切,这个就不是模型的问题,而是代码规范的问题,例如这一块是干嘛的,模型命名是不是见名思义,又或者是代码没有分层,所有的业务逻辑往控制器和模型里死怼?
不使用模型,工作量真的会增大(模型替换成SQL语句查询),而且还要顾及到SQL注入的问题。
“SQL 复制下来就可以贴到数据库工具里跑了,调试、调优”,其实Eloquent也有对应的调优的方式,比如避免N+1的问题,比如输出相应sql语句。
感觉完全舍弃Eloquent ORM有点舍本求末了!

2年前 评论

讨论这个问题的时候可以先想一下 ORM 为我们做了什么:

  1. tablemodel 按一定规则绑定
  2. curd model 变成 对应的 sql(包含参数处理)
  3. sql 的结果映射到 model
  4. 抽象 sql 语义,做到换 db 不需要改 orm 代码

上面博主 leader 想要的其实只有 orm 的第三点功能(参数处理已经包含,不存在注入问题),实际的开发过程中,换数据库的可能性比较低第四点可以比较不用纠结。

下面可以讨论一下 开发效率问题: 在实际开发中一般是读8、写2,讨论对于查询逻辑的考虑就可以看到到底影响有多少。

假设你要获取一个 用户信息(单表查询)

// 伪代码
// 1. sql

$user = $db->sql('select a,b,c from user where id=:id')->bindValue(':id',1)

// 2. orm
$user = User::find()->where(['id' => 1])

上面两个写法都是一行就能解决掉,效率没差很多吧,并且每一条查询都是有意义的, 一般来说都会被包装成一个服务的方法,比如上面的一句应该被包装在 UserService::GetById(id) 中。 使用 ORM 可能让你觉得很快,快在你可以再各个地方 ORM 出你要的数据,但是其实当正确的使用不能到处随意用的时候 也没有快到哪里去。

在说一点,关于 慢 sql 的快速排查,为啥 dba 通过检测工具发现慢 sql 的时候,我不能直接把 sql 拿到项目中全文搜索到, 为啥我要通过监听,然后到日志中去查找。按照最直观的就是直接 搜索项目就完事了。

2年前 评论
Imuyu 2年前
amoy_jz (作者) 2年前
Imuyu 2年前
amoy_jz (作者) 2年前
amoy_jz (作者) 2年前
zl4u 2年前
Complicated

我感觉就是纯为了调试 方便,就是那句“SQL 复制下来就可以贴到数据库工具里跑了,调试、调优都需要。动态生成的,拿到原始语句很困难” :joy:

2年前 评论
半人间 2年前
哪吒的狗腿子 2年前
oceanjiayu 2年前
诺墨 2年前

感觉你们领导们不太懂PHP代码调试,以及对SQL 注入没太有概念。

2年前 评论

这个工程量有点大

2年前 评论
aab

既然讨厌AR就可以使用 DataMaper 的模式,数据获取的逻辑自己封装,数据获取完成之后在转换到具体的对象中,这里的好处就是很容易处理 Laravel ORM 中不太好搞的关联表聚合成为一个Model。不过纯手写 SQL 给人的压力是比较大的,很容易引入SQL的注入,这种情况下可以引入一个 QueryBuilder 不过看文章的意思估计Leader也不会喜欢。

2年前 评论

叫你领导不要用框架.

2年前 评论
一念沧海一念桑田 1年前
playmaker

难道为了调试 就不能装个 Clockwork
这种不香吗?

Laravel

2年前 评论
晏南风 2年前

ORM用的不规范调试确实让人崩溃

2年前 评论
薄荷蓝的晴天 2年前
chenyu0257 2年前

看戏模式先

[自己写sql有laravel的orm防注入更好吗]

2年前 评论

可以试试 Telescope,不用 ORM 还是舍本逐末吧,PHP 不就是要快吗,自己手敲 SQL,能快到哪里去。

2年前 评论

手敲SQL这工作量和开发体验也太糟糕了吧,维护起来也麻烦啊
我上次看到一个CMS,拿到模型对象了,还要在封装一个助手函数

Helper::model('user')->update([], $user->id);

类似这么调用

2年前 评论

很好调试。写 ORM,肯定要对比,测试,性能分析,然后上线就没问题了。

2年前 评论
Summer

使用 ORM ,约定俗成的东西,相当于代码层面规范化了,让大家写出来的代码都差不多,反而更好维护,安全性也更好。

关于:

SQL 复制下来就可以贴到数据库工具里跑了,调试、调优都需要。动态生成的,拿到原始语句很困难。

除了 toSql() 方法,上面的朋友也提到了,很多工具可以轻松拿到 SQL 语句。

对于 IDE 对 obj [“MyField”] 的支持,确实是硬伤。

2年前 评论
大张 2年前
Summer (作者) 2年前
薄荷蓝的晴天 2年前
Summer (作者) 2年前
GeorgeKing 2年前
cvoid 2年前
GeorgeKing 2年前
cvoid 2年前
GeorgeKing 2年前
大张 2年前

???????????? :joy: :joy: :joy:

2年前 评论

我们公司都是严格用模型的

2年前 评论

ORM的出现本来就是为了规范开发和安全,Eloquent 内部使用的是 PDO 参数绑定,所以大部分的请求是安全的。
你所说的90%的时间在找关于模型的一切,这个就不是模型的问题,而是代码规范的问题,例如这一块是干嘛的,模型命名是不是见名思义,又或者是代码没有分层,所有的业务逻辑往控制器和模型里死怼?
不使用模型,工作量真的会增大(模型替换成SQL语句查询),而且还要顾及到SQL注入的问题。
“SQL 复制下来就可以贴到数据库工具里跑了,调试、调优”,其实Eloquent也有对应的调优的方式,比如避免N+1的问题,比如输出相应sql语句。
感觉完全舍弃Eloquent ORM有点舍本求末了!

2年前 评论

丧心病狂啊,越这样反而越不好维护;新人登场,脱离主流反而不好

2年前 评论
pndx

这代码之后维护的人会怎么想?

2年前 评论

说一个orm的点,当线上出现慢sql时,根据sql语句去定位时,可能不太方便

2年前 评论
zl4u (作者) 2年前
chowjiawei 2年前
chowjiawei 2年前
大张 2年前
chowjiawei

你们领导50岁了????

2年前 评论

既然领导开心用原生 SQL,就迎合他嘛,也不是触碰底线的事;

ORM 用多了,现在写个 SQL 都得看文档~

2年前 评论

这两天正在弄 JAVA ,我怀疑你的领导是写 JAVA 的 :grin: 我现在正在想办法把 SpringData JPA 封装个跟 laravel 差不多的查数据库的类,已经新建好了文件,就缺同时会 JAVA 和 PHP 的大佬指点了

2年前 评论

之前认识一个C#的老哥,他的确能做到一条sql,直接查出非常复杂的数据,估计是他的习惯吧。

2年前 评论

JAVA 里面查询数据,很多都是下面这样写的,用过 PHP 的,再用这个感觉不太习惯

file

file

2年前 评论
22 (作者) 2年前
aab 2年前
翟宇鑫

自己不会使用一些便携工具,却非要回归原始
永远守着自己几十年前那本就一知半解的知识
受罪的是大家
只是他自己这几十年下来可能习惯了,别人会觉得很扯淡

2年前 评论

这个leader不行啊

2年前 评论
windawake

orm好比mysql的template。mysql源码如果不使用template,每几个月还能做到升级一个小版本吗?说到底就是领导为了拿线上有问题的sql,然后去项目代码搜索找到对应开发负责人,好让自己天天可以写ppt

2年前 评论

这个leader不得行。不会用就说别人不好用

2年前 评论

可以推荐给你领导,使用ORM的简单查询,不要用生成的关联复杂查询,方便后期优化 :joy:

2年前 评论
orange1994

我们就是原生代码,写起来蛮爽的。

2年前 评论

:joy: 只要不加班 就慢慢磨吧 而且还有正当理由 原生sql速度肯定要慢得多

2年前 评论
sanders

ORM 某种以上说就是一种约束,多少问题直接查模型就解决了。

自己写 SQL 的话,你们头还得订更多 SQL 书写的规范,比如聚合查询别名的命名规范,子查询的书写规范,表别名规范等等。

2年前 评论

如果能写出优质的sql,肯定是写原生比ORM好。而且也不存在安不安全的问题,ORM不也是PHP封装的吗?除非有人对接收的参数不做数据绑定和过滤。ORM有时候用起来的确很方便,但是一些复杂的sql语句如果硬要用ORM写,太耗时间了特别是不熟悉ORM的情况下。没有谁比谁好,只有谁比谁更适合于某个场景。

2年前 评论

人和代码有一个能跑就行

2年前 评论

人和代码有一个能跑就行

2年前 评论
陈先生
  1. 让你领导不要使用框架
  2. 说服他告诉他有事件监听,一样可以随时拿到 SQL
  3. 如果直接 SQL 出现了任何安全问题都要你的领导背锅
  4. 不行就换个领导吧 总结 我不认为这份经历会给你带来任何正收益,不主张 ‘不做xx/不使用xx 一定是错的’,但是现在已经不是手写 SQL 的时代了,你的领导为了所谓的安全性,却带来了更多的负收益。 以上均为个人观点,认同与否雨我无瓜。
2年前 评论

装个 laravel-debugbar 不香吗?

2年前 评论

我个人也推荐裸写PDO, :joy:

2年前 评论

讨论这个问题的时候可以先想一下 ORM 为我们做了什么:

  1. tablemodel 按一定规则绑定
  2. curd model 变成 对应的 sql(包含参数处理)
  3. sql 的结果映射到 model
  4. 抽象 sql 语义,做到换 db 不需要改 orm 代码

上面博主 leader 想要的其实只有 orm 的第三点功能(参数处理已经包含,不存在注入问题),实际的开发过程中,换数据库的可能性比较低第四点可以比较不用纠结。

下面可以讨论一下 开发效率问题: 在实际开发中一般是读8、写2,讨论对于查询逻辑的考虑就可以看到到底影响有多少。

假设你要获取一个 用户信息(单表查询)

// 伪代码
// 1. sql

$user = $db->sql('select a,b,c from user where id=:id')->bindValue(':id',1)

// 2. orm
$user = User::find()->where(['id' => 1])

上面两个写法都是一行就能解决掉,效率没差很多吧,并且每一条查询都是有意义的, 一般来说都会被包装成一个服务的方法,比如上面的一句应该被包装在 UserService::GetById(id) 中。 使用 ORM 可能让你觉得很快,快在你可以再各个地方 ORM 出你要的数据,但是其实当正确的使用不能到处随意用的时候 也没有快到哪里去。

在说一点,关于 慢 sql 的快速排查,为啥 dba 通过检测工具发现慢 sql 的时候,我不能直接把 sql 拿到项目中全文搜索到, 为啥我要通过监听,然后到日志中去查找。按照最直观的就是直接 搜索项目就完事了。

2年前 评论
Imuyu 2年前
amoy_jz (作者) 2年前
Imuyu 2年前
amoy_jz (作者) 2年前
amoy_jz (作者) 2年前
zl4u 2年前

只能说是闲的,老板给的需求做太快了

2年前 评论

换 java 吧

2年前 评论

如果换原生sql就用Go吧 我觉得原生开发效率差不多啊

2年前 评论
amoy_jz 2年前

不用ORM,用原生sql绑定参数方式 那真是脑壳疼啊。

2年前 评论
九霄道长

本质上还是规范造成的一系列问题。

2年前 评论
李铭昕

如果只是为了定位,,那这种方式有点蠢,其实很简单,把所有的 SQL 都打印出来,然后记录对应执行时间,打印的同时,也记录当前 Request 的 uuid,这样就很快可以定位到某个接口,那么顺着接口排查就行了。用不了几分钟就可以找到对应的位置。

2年前 评论
"(select {$cfield} from (select co.*,sum(cop.package) as total_package,sum(if(cop.is_fixed=1||cop.is_fixed=3,0,cop.weight)) as total_weight,(sell_amount - sum(cop.cost)) as newprofit 
            from (select {$convertFields} from convert_order b left join ({$convertSellQuery} union all {$convertClientQuery}) tmp on tmp.batch_number = b.batch_number left join warehouse w on w.warehouse_id = b.in_warehouse_id where ".$convertWhere." group by b.batch_number".") 
            co left join convert_order_product cop on cop.convert_order_id = co.buy_id and cop.is_deleted = 0 and cop.state = 0 group by co.batch_number) sp)"

像这种sql 你让他来维护一下他就知道头有多疼了 :joy:

2年前 评论
kolin (作者) 2年前
小李世界 2年前
yaoxs 2年前
kolin (作者) 2年前

我个人倾向于使用ORM 但是禁用关联查询。

2年前 评论
Complicated 2年前
apud 2年前
apud 2年前
mowangjuanzi (作者) 2年前
apud 2年前
mowangjuanzi (作者) 2年前
JeffreyBool

是你们领导太菜了,对于复杂的sql 不建议使用 orm 特性,简单的查询用 orm 挺好用的,现在基本都是微服务架构,查询都是简单查询,联表查询都很少,所以用 orm 还行,而且可以在框架层面增加改动,将执行 sql 在执行的时候输出到日志,类似下面的日志

{"level":"info","ts":"2022-02-11T12:02:09.569+0800","caller":"logger/gorm.go:102","msg":"[SQL]","app_id":"platform.data.messagejob","instance_id":"xxxxxxx","env":"testing","span_id":"7a635aa7ebde91b8","trace_id":"47e114072e279bf5","sql":"INSERT INTO `message_03` (`send_id`,`uid`,`obj_id`,`obj_type`,`sub_obj_id`,`sub_obj_type`,`reason`,`task_id`,`content_id`,`is_read`,`state`,`created_at`,`updated_at`,`id`) VALUES (1433226191988326404,1433226191988326403,1433226191988326403,'1',0,'1','event.asset.move',-4117755899492170617,1491985885690855424,'0','0','2022-02-11 12:02:09.562','2022-02-11 12:02:09.562',1644552129000086)","rows":1,"start":"2022-02-11T12:02:09.568+0800","cost":"0.913ms","caller":"/builds/platform/platform.data.messagejob/internal/data/db/message.go:32"}
2年前 评论

一直用的原生sql,绑定参数的方式. 很少用orm,虽然也会用,别人问就是你想用哪个就用哪个.

像我这边有很多复杂的业务,如果用orm你会陷入如到一个怪圈.原生sql也复杂,不过好于orm.orm的方法有很多,精通的人很少,如果有人写了修改器或者获取器,稍微菜的人看你代码会直接崩溃.这从哪里来的.

还有个例子,比如用redis.你用laravel框架只知道把驱动设置成redis,用Cache门脸就行.多简单啊.但是redis是有自己的调用语法,比如SETEX jiyikey 60 redis.说白了还得是充实自己.把orm用的再6,换个框架还得重新看.

如果只是完成任务代码就当我没说

2年前 评论
aab 2年前
Diudiuuuu (作者) 2年前

一般orm框架不都有打印sql的功能吗?

2年前 评论

如果用ORM,那么你既得学会使用ORM,又得学会使用SQL,因为面试往往问的都是SQL。

而如果用SQL,那么你只需要学会SQL就好了。

2年前 评论

本来就是相互配合的东西,orm这个东西除了提高开发效率,有时候也是规范,方便维护。如果真的有部分不适合你的操作,就自己再去修改或者封装,没必要抛弃,这里并不是二选一。

1年前 评论

这次我站你们领导 :kissing_heart: 你们领导的出发点应该是sql语句的执行效率问题,没考虑代码组织的维护问题 关于sql怎么写,写到哪,这个需要设计一下,全写完整sql语句不是不可以,最好保证这个sql可以多个地方复用

1年前 评论

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