我来自非 SQL 数据库 (MongoDB),我正在构建一个新项目,但使用的是 MySQL(关系数据库)。
我正在制作一个餐厅系统,在这个系统中,有一个页面,您可以在其中创建产品并描述其成分。
在 MongoDB(非 SQL 数据库)中,您可以为您的文档创建此模式(我将使用 JSON 来描述它只是为了说明要点):
// imagine this is a document of a product stored in the products collection
{
name: "Burger",
price: 200,
ingredients: [
{ name: 'tomato', qty: 2 }, // qty: ie quantity
{ name: 'cheese', qty: 1 },
{ name: 'bread', qty: 2 },
{ name: 'meat', qty: 1 },
]
}
但是,在 SQL 关系数据库中,您必须创建类似于以下内容的内容:
乍一看很难看,但仔细一想,现在也开始习惯了。
首先,我想问一个关于这种方法的问题:
- 这是解决这个问题的方法吗?
我相信您已经数百次遇到过这种情况。
其次,我还有一个问题:
现在用户按下了“创建”按钮来创建他的产品,他向服务器发送了请求来处理这个请求,
我如何将这些行插入数据库?!
是通过做一个for循环并向数据库发送5个请求:
- 第一个请求是在产品成分表中创建ID#1的行。
- 第二个请求是在产品成分表中创建ID#2的行。
- 第三个请求是在产品成分表中创建ID#3的行。
- 第四个请求是在产品成分表中创建ID#4的行。
- 第五个也是最后一个请求是在产品表中创建ID#1的行。
这看起来有点疯狂。
这就是我的大脑在说什么。
这就是为什么我特别问这个问题。
后面会有一个更新的产品页面,类似的for循环,一堆请求,要在数据库上执行。
现在的问题是如何。
我感谢所有愿意将我的大脑带入关系数据库世界的人。?
?这是解决这个问题的方法吗?
简短的回答 - 是的。
先插入产品。
然后检索自动分配给新创建的产品行的 ID。
然后循环遍历成分,依次插入每个成分,在每个成分中使用新的产品 ID。
这取决于变化。
更改产品中的单一成分可能需要一次更新。通过丢弃所有成分并重新插入它们,可能更容易完成更多的“横向”更改。YMMV。
不,落后。
product
首先,您在表中创建一行。在客户端。ingredients table
. 每个新行都会立即保存。product-ingredients
表格创建行,该产品的每种成分一行。实际上 - 在步骤 2 中创建的每一行都会立即单独保存,您需要针对每种成分进行查询。当然,您可以收集这些数据并在一个查询中保存所有新创建的成分,但这在交互模式下没有任何意义。在步骤 1 和 3 中创建的行在步骤 4 中保存。这需要 3 个查询。第一个查询保存产品,第二个查询检索其标识符,第三个查询保存所有关系行。
除了其他人所说的,以帮助填补一些空白:
正如 Akina 所说,这取决于情况,但如果 30 种成分都不存在,那么是的,一种方法是
INSERT
为每种成分执行单独的语句。但是根据您的应用程序的架构方式,您可以将这些INSERT
语句放在同一批中,这样一次只需要向数据库发出一个请求。在合理可能的情况下,不要对数据库发出太多不必要的额外请求是一种很好的做法。此外,在某些数据库系统中,当语句数量很多
BULK INSERT
时,您可以使用一种方法。这不仅会在一个请求中包含所有成分,还会在单个语句中,利用最佳方式将其放入表中。INSERT
INSERT
INSERT
Akina 提到单个
INSERT
语句需要几毫秒,但即使这样也高估了。30 种成分等是极少量的数据。INSERT
单个语句的执行时间不应超过一毫秒,实际上可能是几纳秒。所以是的,INSERT
进入表格应该非常快,因为你正在谈论的数据量。这就是交易的目的。它们确保包装在它们内部的每个数据操作语句 (DML) 都以原子方式执行——要么全部执行,要么什么都不执行。如果一个语句出错,它们都会回滚。否则他们都会一起成功。
不可能。一旦发出回滚(由数据库系统根据错误自动执行,或由您的代码手动指示),它必须完成。数据库系统有一个日志,用于确保原子性和一致性(这是符合 ACID 的数据库系统的ACID 原则的一部分 - 大多数 RDBMS)。回滚命令会立即记录在日志中,因此如果发生任何事情(例如数据库服务器崩溃),它会知道在服务器重新联机时停止的位置,以便它可以恢复协调回到数据库的有效一致状态。