【问题标题】:CRON Job Send email to users in DB?CRON 作业 向 DB 中的用户发送电子邮件?
【发布时间】:2015-05-09 00:08:22
【问题描述】:

如果我有一个填写表格的用户数据库,我可以使用 cron 作业发送自动电子邮件吗?如果是这样,“循环”它以向每个用户发送一次电子邮件的最佳方法是什么?

$data = mysql_query("
SELECT *
FROM completed
WHERE
followupsent='0000-00-00 00:00:00'
AND valuesent + INTERVAL 4 DAY <= NOW()
")
or die(mysql_error()); 

while($info = mysql_fetch_array( $data )) 
{
}

这会检查“followupsent”是否已经更新,因为它在发送时会更新为NOW(),还会检查自发送值以来的天数。

我担心将电子邮件发送信息放在 while 标记中会为每一行循环并最终发送大量电子邮件。

将使用和if 代替while

if($info = mysql_fetch_array( $data )) 
{
}

为了发送到数据库中的第一个,然后让 cron 作业通过每分钟检查下一个是哪个来处理其余的?

【问题讨论】:

  • 您始终可以发送 单个 封邮件,其中所有收件人都是盲复制的。
  • 嗨,嗯,我真的不明白你在一段时间内为每个用户发送电子邮件的问题是什么,同时从你的表中获取值,你不想发送 1000 封电子邮件30秒 ?是的,你可以按照@eggyal 所说的去做
  • @eggyal 从数据库中调用了与每个用户相关的特定详细信息,因此密件抄送在发送相同的电子邮件时不起作用。
  • 很公平。那么,正如@user3742755 所问的那样,您对从while 循环中发送单独的电子邮件有什么顾虑?
  • @user3742755 我读到,如果您有 500 个用户都在等待电子邮件,则使用 while 循环 CRON 作业将运行,并尝试发送电子邮件,但在更新数据库之前,它再次运行,从而多次发送电子邮件...?

标签: php mysql email cron


【解决方案1】:

这是一个非常好的方法。每条记录只会发送一次(因此假设您已完成的表中没有重复项)。

我假设您正在更新循环中的 valuesent 字段

【讨论】:

  • 没错。我主要担心的是它会尝试发送 500 封电子邮件,不会更新,然后 cron 作业会再次运行并尝试向同一个人发送另外 500 封电子邮件?
  • 当然,如果您的更新查询中有错误。显然先测试一下。但是,无论您是一次性完成所有操作还是一次完成 1 个操作,您都会遇到同样的问题。
  • 但如果 CRON 作业一次只运行一封电子邮件,那么它将移动到下一行,并且邮件已经完成。如果 CRON 作业启动,但 while 循环没有完成并更新尚未完成的行,它会尝试再次发送到所有这些行吗?然后一次又一次?
【解决方案2】:

我建议:

  1. 您确保您的 completed 表使用事务存储引擎,例如InnoDB:

    ALTER TABLE completed ENGINE=InnoDB;
    
  2. 您定义了一个新的 BOOLEAN 列,该列指示(对任何其他数据库连接)给定记录正在更新:

    ALTER TABLE completed ADD COLUMN updating BOOLEAN NOT NULL DEFAULT FALSE;
    
  3. 您使用locking readSELECT 要通过电子邮件发送的记录,然后在同一事务中使用UPDATE 到新创建的列。例如,使用PDO:

    $dbh->beginTransaction();
    
    $select = $dbh->query('
      SELECT *
      FROM   completed
      WHERE  followupsent IS NULL
         AND valuesent <= CURRENT_TIMESTAMP - INTERVAL 4 DAY
         AND NOT updating
      FOR UPDATE
    ');
    
    $dbh->exec('
      UPDATE completed
      SET    updating = TRUE
      WHERE  followupsent IS NULL
         AND valuesent <= CURRENT_TIMESTAMP - INTERVAL 4 DAY
         AND NOT updating
    ');
    
    $dbh->commit();
    
  4. 然后,您可以在发送每封电子邮件时更新数据库(删除 updating 标志以及您需要的任何其他状态):

    $success = $dbh->prepare('
      UPDATE completed
      SET    followupsent = CURRENT_TIMESTAMP,
             updating = FALSE
      WHERE  id = ?
    ');
    
    $failure = $dbh->prepare('
      UPDATE completed
      SET    updating = FALSE
      WHERE  id = ?
    ');
    
    foreach ($select as $row) {
      $command = mail(...) ? $success : $failure;
      $command->exec(array($row['id']));
    }
    

请注意,如果脚本过早终止,数据库可能会处于不良状态——即记录可能有updating=TRUE,但不再有任何脚本正在处理它们;这可能会导致某些记录根本无法通过电子邮件发送。您可能希望通过registering a custom shutdown function 来防范这种可能性,或者通过定期检查数据库中的此类“孤立”记录(当然,您必须确保它们当前没有被正在运行的脚本处理)。

【讨论】:

  • 现在只是尝试一下,我从来没有使用过 PDO 并使用 MySQL 或 MySQLi,当您调用 $dbh->exec/prepare 等时,基本上只是 PDO 连接到数据库吗?编辑:看着它,我不知道如何将它翻译成 MySQL。我从未在 SELECT 的末尾看到 FOR UPDATE 标记。这在 MySQL 中有效吗?它有什么作用?干杯
  • @BN83:点击我回答中的链接。他们比我解释得更好。
猜你喜欢
  • 2011-04-26
  • 1970-01-01
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-27
  • 2016-09-13
相关资源
最近更新 更多