PHP PDO 事务?

Posted

技术标签:

【中文标题】PHP PDO 事务?【英文标题】:PHP PDO Transactions? 【发布时间】:2012-04-26 17:02:12 【问题描述】:

我有一个注册页面,基本上我需要将数据插入 4 个表中。我是 PDO 的新手,对某些事情感到困惑。

基本上,如果任何插入失败,我不希望将任何内容添加到数据库中,这似乎很简单。

我的困惑是,我需要先在我的users 表中插入用户的用户名、电子邮件、密码等,这样我才能使用 PDO 获取(不知道如何)mysql 给我的用户的 uid(由 mysql 自动递增) .我需要用户 uid MySQL 为其他表提供了我的用户,因为其他表需要 uid,因此所有内容都正确链接在一起。我的表是 InnoDB,我有从 users_profiles(user_uid)、users_status(user_uid)、users_roles(user_uid) 到 users.user_uid 的外键,所以它们都链接在一起。

但同时我想确保如果例如在users 表中插入数据之后(这样我就可以获得 MySQL 给用户的 uid),如果任何其他插入失败,它会删除数据插入到users 表中。

我认为最好展示我的代码;我把代码注释掉了,在代码中做了解释,可能会更容易理解。

// Begin our transaction, we need to insert data into 4 tables:
// users, users_status, users_roles, users_profiles
// connect to database
$dbh = sql_con();

// begin transaction
$dbh->beginTransaction();

try 

    // this query inserts data into the `users` table
    $stmt = $dbh->prepare('
                        INSERT INTO `users`
                        (users_status, user_login, user_pass, user_email, user_registered)
                        VALUES
                        (?, ?, ?, ?, NOW())');

    $stmt->bindParam(1, $userstatus,     PDO::PARAM_STR);
    $stmt->bindParam(2, $username,       PDO::PARAM_STR);
    $stmt->bindParam(3, $HashedPassword, PDO::PARAM_STR);
    $stmt->bindParam(4, $email,          PDO::PARAM_STR);
    $stmt->execute();

    // get user_uid from insert for use in other tables below
    $lastInsertID = $dbh->lastInsertId();

    // this query inserts data into the `users_status` table
    $stmt = $dbh->prepare('
                        INSERT INTO `users_status`
                        (user_uid, user_activation_key)
                        VALUES
                        (?, ?)');

    $stmt->bindParam(1, $lastInsertID,     PDO::PARAM_STR);
    $stmt->bindParam(2, $activationkey,    PDO::PARAM_STR);
    $stmt->execute();

    // this query inserts data into the `users_roles` table
    $stmt = $dbh->prepare('
                        INSERT INTO `users_roles`
                        (user_uid, user_role)
                        VALUES
                        (?, ?)');

    $stmt->bindParam(1, $lastInsertID,      PDO::PARAM_STR);
    $stmt->bindParam(2, SUBSCRIBER_ROLE,    PDO::PARAM_STR);
    $stmt->execute();

    // this query inserts data into the `users_profiles` table
    $stmt = $dbh->prepare('
                        INSERT INTO `users_profiles`
                        (user_uid)
                        VALUES
                        (?)');

    $stmt->bindParam(1, $lastInsertID,      PDO::PARAM_STR);
    $stmt->execute();

    // commit transaction
    $dbh->commit();

 // any errors from the above database queries will be catched
catch (PDOException $e) 
    // roll back transaction
    $dbh->rollback();
    // log any errors to file
    ExceptionErrorHandler($e);
    require_once($footer_inc);
    exit;

我是 PDO 的新手,上面可能存在我尚未注意到的错误或问题,因为在找出问题之前我无法测试。

    我需要知道如何首先在 users 表中插入用户数据,以便获取 MySQL 给我的用户的 uid

    然后获取其他表需要的 uid

    但同时,如果在插入用户表后查询因任何原因失败,则数据也会从用户表中删除。

【问题讨论】:

a) 将 $dbh->beginTransaction(); 和之前的行放在 try/catch 块之外 - 在事务启动之前,您无法回滚任何内容。 b)什么不适合这个?照常使用 lastInsertId 即可。 @Niko,我马上就做,谢谢 phplover @Niko,我编辑了上面的代码以反映您所说的更改,我能问一下为什么$dbh->beginTransaction(); 也不能在 try 块中吗?有点不太明白,谢谢phplover 只检索 ID 而不使用它没有任何意义,对吧?应该是这样的:$userId = $dbh->lastInsertId(); - 我不认为从 try/catch 块中调用 beginTransaction() 真的会导致问题,但是如果开始事务失败并且引发了 PDO 异常,你会在开始之前尝试回滚事务。这会导致未定义的行为,很可能是一个新错误。除此之外,您一切都做得很好。 【参考方案1】:

此函数返回刚刚插入记录的主键:PDO::lastInsertId NEED_USERS_UID_FOR_HERE 参数将需要它。在 INSERT 语句之后使用它。

自从您启动事务以来,如果您对 MySQL 表使用 InnoDB 引擎(MyISAM 不支持事务),则如果发生任何错误,数据将不会插入任何表中。

【讨论】:

谢谢我想我现在明白了,我把$dbh->lastInsertId(); 放在 INSERT 语句之后(参见原始帖子中的编辑代码),现在我得到了最后一个插入 id 做你上面说的,如何我现在是否可以访问最后一个插入 ID 以将其放入其他查询 NEED_USERS_UID_FOR_HERE 中?抱歉,我是 PDO 的新手,所以还在搞清楚,谢谢 phplover 对不起,我可以更好地解释一下,我是否只需将变量分配给$dbh->lastInsertId();,使其变为$lastInsertID = $dbh->lastInsertId();,然后在上面写着NEED_USERS_UID_FOR_HERE 的地方只需将其替换为$lastInsertID ?谢谢phplover 是的。只需将其存储为变量并在进一步的查询中使用它。事务失败时不会写入数据库。 FractalizeR 和 Niko 都提供了很好的答案,这对我有帮助,很难选择一个接受的答案,但是因为 FractalizeR 是第一个回复的,并且会选择你的作为接受的答案。感谢你们俩的帮助,phplover,几分钟后会测试一下。

以上是关于PHP PDO 事务?的主要内容,如果未能解决你的问题,请参考以下文章

PHP PDO 事务问题

PHP PDO 事务自动回滚

PHP PDO 基础知识

PHP使用PDO进行事务处理

PHP中PDO事务的使用方法

PHP PDO 事务?