likes
comments
collection
share

数据库ORM及操作数据库的三层抽象概述(Node.js为例)

作者站长头像
站长
· 阅读数 2

什么是ORM?

ORM框架:Object Relational Mapping,对象-关系-映射,所以说ORM框架就是用面向对象的方式和目前的关系型数据库做匹配。

为什么会有ORM?

它解决了对象和关系型数据库之间的数据交互问题。

数据库ORM及操作数据库的三层抽象概述(Node.js为例)

1、业务代码中手写SQL容易出错

而有了 ORM 技术以后,只要提前配置好对象和数据库之间的映射关系,ORM 就可以自动生成 SQL 语句,并将对象中的数据自动存储到数据库中,整个过程不需要人工干预。 在 node 中,ORM 一般使用 类 或者注解来配置对象和数据库之间的映射关系。

2、字段类型的静态检查

Int number '2222'

比方我数据库定义了一个id字段类型为 Int orm中定义为number, 假设我用orm操作数据库的时候id我传了字符串, 静态检查就会给我报错。

3、提高开发效率

orm避免了简单且重复的查询直接手写sql, 提高的开发效率。

4、缓存

比方我查网站首页一个东西,需求呢缓存1分钟, 那么orm也可以来帮我做,加个配置字段, 相同的sql就会缓存结果。

orm的缺点

ORM 在提高开发效率的同时,也带来了以下几个缺点:

  • ORM 增加了大家的学习成本,为了使用 ORM 技术,您至少需要掌握一种 ORM 框架。
  • 自送生成 SQL 语句会消耗计算资源,这势必会对程序性能造成一定的影响。
  • 对于复杂的数据库操作,ORM 通常难以处理,即使能处理,自动生成的 SQL 语句在性能方面也不如手写的原生 SQL。
  • 生成 SQL 语句的过程是自动进行的,不能人工干预,这使得开发人员无法定制一些特殊的 SQL 语句。

复杂sql示例 像如下需要关联多个表, 各种计算的复杂的查询,显然,orm是满足不了的, 这时候就需要手写。

static async getExtendOrderCommodity(uid, ordernos = null) {
  let SQL = `
      SELECT
        a.orderno,
        a.buy_num buyNum,
        round(a.period * 365) AS period,
        a.increase_capacity increaseCapacity,
        b.commodityname,
        b.power,
        b.min_capacity minCapacity,
        b.max_capacity maxCapacity,
        d.start_at startAt,
        DATE_ADD(d.start_at,INTERVAL a.period year) lastTime,
        d.end_at endAt
      FROM
        order_info a
        INNER JOIN commodity b ON a.commodityid = b.id
        INNER JOIN order_related_sn c ON a.orderno = c.orderno
        LEFT JOIN deposit d ON c.sn = d.sn 
        AND c.uid = d.uid 
      WHERE
        a.uid = ? 
        AND b.expend_status = 1
        AND c.deposit_status = 1
        AND a.complete = 1
        AND a.increase_capacity = 0
        AND a.deleted_at IS NULL
    `;

  if (Array.isArray(ordernos)) {
    SQL += ` AND a.orderno IN (${ordernos.join(',')})`;
  }

  SQL += ` GROUP BY a.orderno`;

  const result = await sequelize.query(SQL, {
    replacements: [uid],
    type: sequelize.QueryTypes.SELECT,
    logging: false,
  });
  return result;
}

数据库与对象之间的映射关系

数据库类/对象
表(table)类(class)
表中的记录(record,也称行)对象(object)
表中的字段(field,也称列)对象中的属性(attribute)

数据库ORM及操作数据库的三层抽象概述(Node.js为例)

操作数据库的三层抽象

由高到低

1、ORM

高层抽象:ORM,建立模型对象到关系型数据库的映射,之后,对模型对象的操作自动映射到数据库中

// select "name" from "users" where "id" = 9527
class User extend Sequlize {
  id
}
User.findOne({
  where: {
    id: 9527
  }
})

2、SQL query builder

中层抽象:SQL Query Builder,生成操作指令。

这一层可以理解为sql构造器,就是你把条件给好,什么表查什么字段,什么条件,它帮你拼接SQL。

但是至于有没有这张表、这个字段, 他是不会感知的,因为他没有关系映射。

例如nodejs中的 knex。

knex.select('name').from('users').where('id', '=', 9527)
//select "name" from "users" where "id" = 9527

3、原生SQL

底层抽象:Database Driver,连接数据库并与之通信,发出操作指令,取回操作结果。

select "name" from "users" where "id" = 9527

操作数据库的控制力和生产力关系图

1、传统的ORM框架虽然生产力高但是可控性低

能满足大部分一般的查询,复杂的需要手写

2、原生SQL语句虽然完全可控但是生产力低

什么意思 自由度高,完全自己控制,但是因为是字符串容易出错,不好排查问题,所以生产力低下。

3、其他SQL查询生成器高可控,中等生产力。

数据库ORM及操作数据库的三层抽象概述(Node.js为例)

最后

ORM这个东西是属于语言层面的,每个语言都有自己的ORM的实现。

但ORM是一种工具,工具确实能解决一些重复,简单的劳动。这是不可否认的。但我们不能指望工具能一劳永逸的解决所有问题,有些问题还是需要特殊处理的,但需要特殊处理的部分对绝大多数的系统,应该是很少的, 对于大部分应用,orm都大大提高了我们开发效率。

小伙伴们都怎么看呢?