我正在开发一个商店系统,我使用我能找到的唯一方法将订单的ID与属于它的产品联系起来。
当有人购买东西时,首先将订单添加到表orders
中,并附上他们的详细信息,包括该订单的ID(order_id
),由SQL自动递增。
我使用这是为了向表orders
添加订单:
INSERT INTO orders SET customer_id = '{$customer_id}', customer_name = '{$user['customer_name']}', order_price = '{$total_price}', order_date = '{$date}'"
好的,订单已添加。现在,按顺序,属于该订单的产品将被添加到另一个表格purchased_products
。
我使用PDO lastInsertId()
从最后插入的order_id
表格orders
然后在另一个名为Foreign Key
的表格中添加该订单的每个产品order_id
purchased_products
。为此,我使用:
$respective_order_id = $connection->lastInsertId();
foreach($_SESSION['cart'] as $product)
{
$sql = "INSERT INTO purchased_products SET order_id = '{$respective_order_id}', product_name = '{$product['product_name']}', product_price = '{$product['product_price']}', quantity = '{$product['quantity']}'";
}
这些代码同时运行。首先,订单将添加到orders
表中,其order_id
自动递增,然后该订单的所有产品也将添加到purchased_products
表和{{1}其中每一个的Foreign Key
将具有order_id
表中插入的最后order_id
的值。稍后我会通过咨询外键orders
来显示产品的任何订单。
到目前为止,它运作良好。正如我所说的,这是我找到的唯一方法,即使用属于它的产品分配订单的ID。我的问题是:这是安全的吗?如果几个人同时购买怎么样?是否存在交换ID或未添加/或订单错误的风险?如果有经验的人回答这些问题,我会非常感激,因为这让我害怕,我想知道我是否可以相信这种方法。
的修改
更多细节!
我的数据库连接:
order_id
我用来在两个表中插入数据的所有代码:
try
{
$connection = new PDO("mysql:host={$HOST};dbname={$DB_NAME}", $USERNAME, $PASS);
}
catch(PDOException $exception)
{
echo "Connection error: " . $exception->getMessage();
}
编辑2更新
有些产品可能有额外的阵列(即颜色),有些则没有。但是默认情况下所有数组都填充了这些数组:$sql = "INSERT INTO orders SET customer_id = '{$customer_id}', customer_name = '{$user['customer_name']}', order_price = '{$total_price}', order_date = '{$date}'"
$query = $connection->prepare($sql);
$query->execute();
$respective_order_id = $connection->lastInsertId();
foreach($_SESSION['cart'] as $product)
{
$sql = "INSERT INTO purchased_products SET order_id = '{$respective_order_id}', product_name = '{$product['product_name']}', product_price = '{$product['product_price']}', quantity = '{$product['quantity']}'";
$query = $connection->prepare($sql);
$query->execute();
}
,product_name
和product_price
。我已经调整了我的逻辑,使用<提供的代码检查额外的参数强> peterm :
product_quantity
如果SESSION中的额外参数数组不为null,则SQL表中的$connection->beginTransaction();
$sql = "INSERT INTO orders (customer_id, customer_name, order_price, order_date)
VALUES (?,?,?,?)";
$query = $connection->prepare($sql);
$query->execute(array
(
$customer_id,
$user['customer_name'],
$total_price,
$date
));
$respective_order_id = $connection->lastInsertId();
$sql = "INSERT INTO purchased_products (order_id, product_name, product_price, quantity, colour)
VALUES (?,?,?,?,?)";
$query = $connection->prepare($sql);
foreach($_SESSION['cart'] as $product)
{
$additional_param = array
(
'colour' => NULL
);
$colour = array_filter($product['colour']);
if(!empty($colour))
{
$additional_param['colour'] = $product['colour']['colour_name'];
}
$query->execute(array
(
$respective_order_id,
$product['product_name'],
$product['product_price'],
$product['quantity'],
$additional_param['colour']
));
}
$connection->commit();
键将填充产品颜色。否则,它将填充SQL colour
。
答案 0 :(得分:2)
使用PDO的lastInsertId()
,取决于驱动程序,但只要您使用正确的自动递增类型的对象(即MySQL中的AUTO_INCREMENT
或PostgreSQL中的序列),就可以安全使用。 MySQL驱动程序使用了LAST_INSERT_ID()
。
如果您关心事务完整性,请考虑将整个操作包装到事务中。这样,它可以全部正确提交或回滚。没有孤立的订单标题行,没有部分填充的订单等。
由于您正在使用PDO 停止进行查询字符串插值。学习并使用prepared statements
一旦开始使用预准备语句,您不仅可以使事情变得更加安全,还可以加快订单详细信息行的插入速度。
是的,我使用AUTO_INCREMENT并在执行前准备所有插入:$ query = $ connection-&gt; prepare($ sql); $查询 - &GT;执行();我只是不明白你的第二个解释。
你目前正在做的事情是无用而危险的。您将查询与值连接(在您的情况下没有任何准备可以这么说),而不是在查询中使用占位符,然后使用绑定值。
更新:以下是您的看法
$colour = array_filter($product['colour']);
$connection->beginTransaction(); // Turn off auto commit and explicitly open transaction
$sql = "INSERT INTO orders (customer_id, customer_name, order_price, order_date)
VALUES (?,?,?,?)"; // Use placeholders in the query. You can use named placeholders if you want to
$query = $connection->prepare($sql); // Prepare the statement
$query->execute(array(
$customer_id,
$user['customer_name'],
$total_price,
$date)
); // Bind the values and execute the statement
$respective_order_id = $connection->lastInsertId();
$sql = "INSERT INTO purchased_products (order_id, product_name, product_price, quantity, colour)
VALUES (?,?,?,?,?)";
$query = $connection->prepare($sql); // Prepare once !!!
foreach($_SESSION['cart'] as $product) {
$query->execute(array(
$respective_order_id,
$product['product_name'],
$product['product_price'],
$product['quantity'],
empty($colour) ? null : $product['colour']['colour_name'], //you can bind null value for nullable columns
)); // Bind and execute multiple times
}
// Explicitly commit the transaction
$connection->commit();