SQL vs SQL Builder vs ORM
与关系数据库对话:SQL vs SQL Builder vs ORM
前言
开发网站无可避免的会和关系数据库打交道,而互动的方式有三种:
- SQL
- SQL Builder
- Object-Relational Mapping (ORM)
这三者有着不同的使用方式、优缺点与适用场景,了解它们的差异能帮助我们做出更适合项目需求的技术选择。
SQL
SQL 是与关系数据库沟通的语言,虽然不同数据库常见语法上有些许差异,但彼此间差异不大。想要获得最好的灵活性与性能可以使用 SQL,极大的灵活性也可能暗藏 SQL Injection 风险。
// ❌ 用户可能添加恶意输入造成拼凑出恶意的 SQL 指令
const username = req.body.username;const password = req.body.password;
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
db.query(query, (err, results) => { if (results.length > 0) { // 登录成功 } else { // 登录失败 }});
// ✅ 通过 Prepared Statement 安全处理用户输入防止 SQL injectionconst username = req.body.username;const password = req.body.password;
const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
db.query(query, [username, password], (err, results) => { // 安全地处理查询});
SQL Builder
介于灵活性与安全性之间的方案,通过抽象函数组合,以代码的方式构建 SQL,从而规避 SQL Injection 问题。
// Drizzle ORMimport { eq, and } from 'drizzle-orm';import { db } from './db';import { users } from './schema';
const username = req.body.username;const password = req.body.password;
const result = await db .select() .from(users) .where(and( eq(users.username, username), eq(users.password, password) ));
if (result.length > 0) { // 登录成功} else { // 登录失败}
ORM
提供一种将数据表映射成程序中的 Class、数据列对应成对象 Object 的方式。通常 ORM 也会处理不同 DB 之间的差异、SQL Injection 问题。
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
const username = req.body.username;const password = req.body.password;
const user = await prisma.user.findFirst({ where: { username, password, },});
if (user) { // 登录成功} else { // 登录失败}
我的学习经验
在 Node.js 生态系统中我使用 MySQL2 与本地数据库沟通,但 SQL 返回的数据没有 TypeScript 类型是一大问题,这个问题通常通过 ORM 框架通过定义好的 Schema 来生成 TypeScript 类型。
发现 ORM 之间的经历转移麻烦且上手难度高,既要理解 ORM 的抽象,又要在必要时能理解其背后的 SQL 会是很头疼的问题,因此我会选择尽可能少量抽象的 SQL Builder 来熟悉 SQL 语法,同时享受它带来的便利,在 TS 生态系统里面推荐 Drizzle ORM 有很完善的 SQL Builder ~ ORM 体验。
总结
特性 | SQL | SQL Builder | ORM |
---|---|---|---|
操作弹性 | 高 | 中 | 低 |
学习门槛 | 低 | 中 | 中 |
安全性 | 低(自行防范) | 高 | 高 |
性能掌控 | 最高 | 高 | 中 |
适合场景 | 着重性能 | 通用 | 增删查改为主 |