疑问:对于反三范式设计下的关系型数据库,是否需要ORM?

先说我提出质疑的原因。

最近看见现在项目中的代码,经常有ORM的写法。

具体来说,用Python的sqlAchemy来写了一些Model。还有Django中的Model,也是object-relation mapping的一些配置。

我之前(大概6年前,2012年)学Java的时候,看了看三大框架SSH,其中H就是一个经典ORM框架。自从用了H以后,语句我也只写HQL了,数据访问对象(data access object)也是写BaseDAO,然后各种继承,泛型、模板、反射使我少写了很多代码。写尤SQL语句非常爽,其实都不是我在写SQL语句了,框架帮我写了。尤其是在做多表联合查询,各种一对多、多对一、多对多的情况下,我还少写了很多对成员变量的封装的代码。框架帮我实现了!懒加载(lazy loading)、事务处理(Tx)再加上spring的openSessionInView,JSP文件中的EL表达式或Java片段,非常轻松地就能实现MVC分层,后台连数据库+前端JSP展示。

CRUD的SQL语句,变成了save、find、update、delete。连hbm文件、Model层的domain对象(entity、pojo),都是用工具对数据库进行逆向工程(reverse engineering),自动生成的。你说方便不方便?

我现在为什么比较反感用ORM呢?(我以前写项目用ORM可是几乎都是写吐了,真的是得心应手啊,尤其是上述的H)

我不是反对它。反而,我要肯定ORM!这种设计非常经典,非常棒!毕竟业务人员不需要把精力过多地放在SQL语句上,专注其业务即可。我曾经那么热衷于H,做的好几个项目,就连我们实验室网站(favor.fudan.edu.cn)也是SSH做的。难道我是见异思迁了?喜新厌旧了?还是我不懂ORM……

是我懒了不想去学习Python里的sqlAchemy,不想去学习Django中的Model吗?是我不懂Model是什么吗?反正总感觉怪怪的。于是我仔细思考,认真思索促使我的态度发生这些变化的那些原因。

目前,我似乎找到了几个说服我自己的原因。

1. 数据库根本就不讲3NF。目前我们用的虽然是关系型数据库,但为了方便,我们用了反3范式的设计。例如,一张表中,我们存有这样的数据。

 

证券代码证券名称成交时间成交价格
601318中国平安9:30:0078.32
601318中国平安9:30:0378.74

如果按3NF的说法,我这种表不被骂上天才怪!

但是,现在是为了方便,为了好查询、好写入,python本来就支持而且建议大家用向量化操作。磁盘空间又不是不够大,冗余?无所谓!

3NF会说,你上面这张表应该拆成2张表!第一,你要设计一张证券表,证券代码和证券名称一一对应。第二,你要设计一张交易表,第一列,证券代码,然后,证券名称全部删掉!

非常正确。但是我要查询呢?我的前端页面需要展示中国平安今天的所有成交记录呢?

我要做两张表的联合查询。为了避免笛卡尔积,我要用主外键关系约束。

select * from t_trade as tt, t_sec_info as ts where tt.sec_code = ts.sec_code and tt.sec_code = '601318'。

或者,分两次查询,第一次查交易表(select * from t_trade where sec_code = '601318'),第二次查证券信息表(select sec_name from t_sec_info where sec_code = '601318')。

在H中,这是一个多对多的问题,拆成多对一和一对多。先查第一张表,EL表达式中,当我去取${trade_item.sec_name}的时候,如果开启了Lazy Loading,可能就查第二张表。然而这一切都已经被框架隐藏了。

此时此刻,H非常好用!

但是对于我那种反3NF的表,H并没有什么卵用。对!无卵用。

select * from t_trade where sec_code = '601318'; 即可。

况且,Pandas已经提供了 pd.read_sql(sql, engine)的函数,返回就是一个dataframe。一句话搞定。不用配置Model,不用考虑各种条件。没有对象依赖,没有多对一、多对多的情况,没有联合查询。不需要联合查询。不需要对象依赖。所有要的信息,都在一张表上。而且,select * 就好。没有更多条件。

没有ORM,我一样可以写出来。而且还更方便。

2. 页面展示,可能就是需要一个<table></table>的东西。不用查询出obj,用所谓的OOP封装一条一条的数据库记录。你就算OOP搞定,是一个个对象,最终还是要放到一个list里, 由控制器交给前端然后再foreach取出来,又放到table的tr和td里面去。pandas的read_sql出来就是一个df。df.to_html()就是一个table。而且,对于flask、django这样的框架,从controller传给view,数据好像一般都是通过json.dumps过去的吧。或者就算是ajax,一般也是json字符串吧。list、object,有什么用呢?过去还要{{data|safe}}取出来,还要转一遍,还要重写view,还要foreach。就用pd.read_sql不好吗?表又不多,经常是一张表,最简单的select * from xxx就好。何乐而不为?

3. 当时有人号称说H可以任意切换数据库,而不改变DAO层的代码。是的,因为框架帮你完成了属于某一种数据库特定的SQL语法的SQL语句。但我就问你,你一个项目要切换很多个数据库吗?你这样的经历很多吗?如果是的,那是你命不好。

……

以上是我的一些看法。供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qcyfred

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值