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

时间:2014-03-14 15:38:07

标签: php mysql pdo

我有3个表,我必须在注册新用户后向他们添加记录:

表格列表:

予。的用户

...... ...... id(auto_increment,primary)

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

II。的博客

...... ...... id(auto_increment,primary)

... ... ... owner_id(=' id' in' users')

III。的事件

...... ...... id(auto_increment,primary)

... ... ... owner_id(=' id' in' users')

... ... ... blog_id(=' id' in' blogs')

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

解决方案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();
}
?>

解决方案2:使用单execute()

<?php 
try {
    // Step 1
    $query = $conn->prepare("INSERT INTO users (email) VALUES (:email);" . 
                            "INSERT INTO blogs (owner_id) VALUES ((SELECT id FROM users WHERE email = :email));" .
                            "INSERT INTO events (owner_id, blog_id) VALUES ((SELECT id FROM users WHERE email = :email), (SELECT id FROM blogs WHERE owner_id = (SELECT id FROM users WHERE email = :email)));");
    $query->bindParam(':email', $email);
    $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();
}
?>

3 个答案:

答案 0 :(得分:3)

我会使用交易作为第一选项的修改。

$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();
}

答案 1 :(得分:0)

编辑。我一开始误解了这个问题,认为你使用的是exec(),而不是执行()。

所以,实际上你可以将两者结合起来,因为lastInsertId只是Mysql的LAST_INSERT_ID()的PHP包装器 但是,由于您需要两个ID,因此设置变量需要额外的混乱。因此,我怀疑第二种选择是否值得,尽管可行。 请注意,仅当PDO仿真模式关闭时,第二个才会起作用

肯定没有像“表演”这样的问题。两者都会完美无缺。

答案 2 :(得分:0)

如果你做了一些基准测试,你会发现大部分时间都会丢失。 从像这样的简单查询的个人基准测试来看,执行时间非常短。 真正花费时间的唯一事情是初始化/准备功能。

制作3个请求会比创建一个大请求慢。

编辑:

选项1是正确的选项,因为你确实需要使用id,不使用字符串链接或其他东西使用id's。

来自那个(准备好的)大查询的公寓比3x准备好。