始终为 m:m 关系 (pupil-evening_activity) 插入行

Posted

技术标签:

【中文标题】始终为 m:m 关系 (pupil-evening_activity) 插入行【英文标题】:Insert rows for an m:m relationship (pupil-evening_activity) consistently 【发布时间】:2017-05-28 21:02:46 【问题描述】:

我的数据库 (mysql/InnoDB) 中有三个表:pupilevening_activitypupil_evening_activity。你可以猜到pupilevening_activity 之间存在m:m 关系。

我有一个 html 表单来插入新学生并将晚间活动与他们联系起来。提交表格后,我想在数据库中插入学生及其相关活动。所以我写了这段代码:

$db = new PDO('mysql:host=localhost;dbname=school;charset=utf8','root', '****');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


try 
    $sql = "INSERT INTO pupil 
            (name, surname) 
            VALUES
            ('test_name', 'test_surname')";
$st = $db->prepare($sql);
$st->execute();

    foreach ($eveningActivityIds as $eveningActivityId)  
    $sql = "INSERT INTO pupil_evening_activity 
                (pupil_id, evening_activity_id) 
                VALUES 
                (?, ?)
        ";
    $st = $db->prepare($sql);
    $st->execute(array($db->lastInsertId(), $eveningActivityId));
    

 catch (PDOException $e) 

echo $e->getMessage();
return false;


我已经写了代码期望PDO::lastInsertId()总是返回最后插入的学生的id,但我发现它真正返回的是最后插入的id整个数据库。因此,如果在假设的teacher 表中插入另一行就在 在上面的代码中调用$db->lastInsertId()$db->lastInsertId() 将返回插入教师的id 而不是@987654334最后一个学生的@。

那么在提交表单后,我如何才能在pupil 表的最后插入id 获得100% 的安全性?

我曾考虑使用事务和MAX() 函数将最后一个id 插入pupil 表中,但我不确定。

【问题讨论】:

【参考方案1】:

在 foreach 循环中使用 $db->lastInsertId() 是错误的,因为它可能会返回不可预测的值。请考虑以下代码:

try 
   $sql = "INSERT INTO pupil 
        (name, surname) 
        VALUES
        ('test_name', 'test_surname')";

   $st = $db->prepare($sql);
   $st->execute();

   // save pupil id into variable here:
   $pupil_id = $db->lastInsertId();

   // also there's no need to prepare the statement on each iteration:
   $sql = "INSERT INTO pupil_evening_activity 
            (pupil_id, evening_activity_id) 
            VALUES 
            (?, ?)";
   $st = $db->prepare($sql);

   foreach ($eveningActivityIds as $eveningActivityId)  
      $st->execute(array($pupil_id, $eveningActivityId));
   
 catch (PDOException $e) 
   echo $e->getMessage();
   return false;

优化:您可以在一个语句中插入所有活动。它为您节省了一些请求

try 
  $sql = "INSERT INTO pupil 
    (name, surname) 
    VALUES
    ('test_name', 'test_surname')";

  $st = $db->prepare($sql);
  $st->execute();

// save pupil id into variable here:
  $pupil_id = $db->lastInsertId();

  $sql = 'INSERT INTO pupil_evening_activity 
        (pupil_id, evening_activity_id) 
        VALUES '; 

  $values = array();

  foreach ($eveningActivityIds as $eveningActivityId) 
    $sql .= '(?, ?),';
    array_push($values, $pupil_id, $eveningActivityId);
  

  $st = $db->prepare(chop($sql, ','));
  $st->execute($values);
 catch (PDOException $e) 
  echo $e->getMessage();
  return false;

【讨论】:

谢谢!很有用!!但是..对我的主要问题有什么想法吗?即:使用PDO::lastInsertId() 将最后一个id 插入pupil 表中是否正确? 我相信这很好,除非你正在构建一个每秒有数千个请求的高负载系统 J.

以上是关于始终为 m:m 关系 (pupil-evening_activity) 插入行的主要内容,如果未能解决你的问题,请参考以下文章

如何在 M:M 中强制执行 1:M 关系?

numpy中的矩阵乘法很奇怪(m * m等于m.dot(m)!!!)[重复]

mysql codeigniter 活动记录 m:m 删除

维吉尼亚密码的Python实现

华为机试真题 Java 实现服务启动

名义利率实际利率名义贴现率