Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/236.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用PDO和PHP执行顺序语句的更好解决方案_Php_Mysql_Pdo - Fatal编程技术网

使用PDO和PHP执行顺序语句的更好解决方案

使用PDO和PHP执行顺序语句的更好解决方案,php,mysql,pdo,Php,Mysql,Pdo,我有3个表,在注册新用户后,我必须向其中添加一条记录: 表格清单: I.用户 。。。id(自动增量,主) 。。。电子邮件(新用户的电子邮件地址) 二,博客 。。。id(自动增量,主) 。。。所有者id(‘用户’中的‘id’) 三、 事件 。。。id(自动增量,主) 。。。所有者id(‘用户’中的‘id’) 。。。blog_id(‘blogs’中的‘id’) 在这种情况下,我找到了两种添加顺序记录的解决方案: 解决方案1:使用lastInsertId <?php try { //

我有3个表,在注册新用户后,我必须向其中添加一条记录:

表格清单:

I.用户

。。。id(自动增量,主)

。。。电子邮件(新用户的电子邮件地址)

二,博客

。。。id(自动增量,主)

。。。所有者id(‘用户’中的‘id’)

三、 事件

。。。id(自动增量,主)

。。。所有者id(‘用户’中的‘id’)

。。。blog_id(‘blogs’中的‘id’)

在这种情况下,我找到了两种添加顺序记录的解决方案:

解决方案1:使用
lastInsertId

<?php 
try {
    // Step 1: add a record to 'users' table and get lastInsertId
    $query = $conn->prepare("INSERT INTO users (email) VALUES (:email)");
    $query->bindParam(':email', $email);
    $query->execute();
    $user_id = $conn->lastInsertId();

    // Step 2: add a record to 'blogs' table and get lastInsertId
    $query = $conn->prepare("INSERT INTO blogs (owner_id) VALUES (:owner)");
    $query->bindParam(':owner', $user_id);
    $query->execute();
    $blog_id = $conn->lastInsertId();

    // Step 3: add a record to 'events' table
    $query = $conn->prepare("INSERT INTO events (owner_id, blog_id) VALUES (:owner, :blog)");
    $query->bindParam(':owner', $user_id);
    $query->bindParam(':blog', $blog_id);
    $query->execute();

} catch (PDOException $e) {
    echo $e->getMessage();
}
?>
我应该选择哪种解决方案来获得更好的性能安全性?有更好的解决方案吗


注意:使用
PDO
创建的连接:

<?php
$options = array(
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
);

try {
    $conn = new PDO("mysql:host=" . App::DB_HOST . ";dbname=" . App::DB_NAME . ";charset=utf8", App::DB_USERNAME, App::DB_PASSWORD, $options);
} catch (PDOException $e) {
    echo $e->getMessage();
}
?>

编辑。我一开始误解了这个问题,以为您使用的是exec(),而不是execute()

因此,实际上您可以将两者结合起来,因为lastInsertId只是Mysql最后一个插入ID()的PHP包装 但是,由于您需要两个ID,因此需要设置一个变量。所以,我怀疑第二种选择是否值得,尽管它是可行的。 请注意,只有在PDO仿真模式关闭的情况下,第二种模式才起作用


当然,没有“表现”这样的问题。这两种方法都会很完美。

如果你做一些基准测试,你会发现大多数时间都会浪费在请求上。 从像这样的简单查询的个人基准来看,执行时间非常低。 唯一真正需要时间的是初始化/准备功能

提出3个请求的速度比创建一个大请求的速度慢

编辑:

选项1是正确的,因为您确实需要使用id,永远不要使用字符串或其他东西链接始终使用id


从1个(准备好的)大查询中选择Appart比3个prepare更好。

我将使用事务作为第一个选项的修改

$conn->beginTransaction();

try {
    // Step 1: add a record to 'users' table and get lastInsertId
    $query = $conn->prepare("INSERT INTO users (email) VALUES (:email)");
    $query->bindParam(':email', $email);
    $query->execute();
    $user_id = $conn->lastInsertId();

    // Step 2: add a record to 'blogs' table and get lastInsertId
    $query = $conn->prepare("INSERT INTO blogs (owner_id) VALUES (:owner)");
    $query->bindParam(':owner', $user_id);
    $query->execute();
    $blog_id = $conn->lastInsertId();

    // Step 3: add a record to 'events' table
    $query = $conn->prepare("INSERT INTO events (owner_id, blog_id) VALUES (:owner, :blog)");
    $query->bindParam(':owner', $user_id);
    $query->bindParam(':blog', $blog_id);
    $query->execute();

    $conn->commit();

}
catch (PDOException $e) {
    // roll back transaction
    $conn->rollback();
    echo $e->getMessage();
    die();
}

如果事件是每个blog的,则不需要用户_id在其中(因为它已经在blog的表中)。如果事件是每个博客的每个用户,则忽略此评论。@SecondRikudo-谢谢,因为您知道实际项目与此简化示例略有不同。所以请忽略这个问题谢谢,只是为了提高我的知识:解决方案2出了什么问题?并不是所有的PHP用户都被误导了。在你的回答中尽量避免“微妙”的暗示和概括。@YourCommonSense:相信我,我有。并不是所有的PHP用户都被误导了。尽量避免在你的回答中出现“微妙”的暗示和泛化。@YourCommonSense:你让我怀疑我从Dexa和你之前的回答中得出的结论。我决定使用选项1,但现在在编辑您的答案后,我无法决定使用哪一个。另外,我发现选项2没有安全问题。@yaa110如果第三次查询失败,您将有一个条目,但没有事件。不确定它是否符合您的逻辑,但通常对于批量插入,您希望全部插入或不插入,这是不可能的autocommit@YourCommonSense我认为这种尝试是可以避免的,我不怀疑你是对的,但如果您能告诉我为什么它不安全,我将不胜感激。向访问者显示任何网站内部信息是一个非常基本的安全缺陷。@YourCommonSense-我会将
display\u errors
设置为
off
,但是,我如何回滚对数据库的所有更改(在任何失败的步骤之后)通过删除try..catch?
如何回滚所有更改
您不需要这样做。就这样吧。实际上,这就是事务的工作方式。您只需要显式提交,而不需要回滚
$conn->beginTransaction();

try {
    // Step 1: add a record to 'users' table and get lastInsertId
    $query = $conn->prepare("INSERT INTO users (email) VALUES (:email)");
    $query->bindParam(':email', $email);
    $query->execute();
    $user_id = $conn->lastInsertId();

    // Step 2: add a record to 'blogs' table and get lastInsertId
    $query = $conn->prepare("INSERT INTO blogs (owner_id) VALUES (:owner)");
    $query->bindParam(':owner', $user_id);
    $query->execute();
    $blog_id = $conn->lastInsertId();

    // Step 3: add a record to 'events' table
    $query = $conn->prepare("INSERT INTO events (owner_id, blog_id) VALUES (:owner, :blog)");
    $query->bindParam(':owner', $user_id);
    $query->bindParam(':blog', $blog_id);
    $query->execute();

    $conn->commit();

}
catch (PDOException $e) {
    // roll back transaction
    $conn->rollback();
    echo $e->getMessage();
    die();
}