如果我有一个已填写表单的用户数据库,我可以使用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 ))
{
}
这将检查"followupsend"是否已经更新,因为它在发送时使用NOW()
进行更新,还将检查发送值后的天数。
我担心,通过将电子邮件发送信息放在while标签中,每行都会循环,最终会发送大量电子邮件。
将使用和if
而不是while
:
if($info = mysql_fetch_array( $data ))
{
}
为了发送到数据库中的第一个,然后让cron作业通过每分钟检查下一个是哪个来处理其余的?
这是一个非常好的方法。它只会在每条记录中发送一次(因此假设您已完成的表中没有重复项)。
我假设您正在更新循环中的valuesend字段
我建议:
-
您确保
completed
表使用事务存储引擎,例如InnoDB:ALTER TABLE completed ENGINE=InnoDB;
-
您定义了一个新的
BOOLEAN
列,该列指示(对任何其他数据库连接)给定记录正在更新过程中:ALTER TABLE completed ADD COLUMN updating BOOLEAN NOT NULL DEFAULT FALSE;
-
您使用对要通过电子邮件发送的记录
SELECT
的锁定读取,在同一事务中,对新创建的列使用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();
-
然后,您可以在发送每封电子邮件时更新数据库(删除
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
,但不再有任何脚本在处理它们;这可能会导致一些记录根本没有通过电子邮件发送。您可能希望通过注册自定义关闭函数或定期检查数据库中的此类"孤立"记录来防止这种情况的发生(当然,您必须确保它们当前没有被运行的脚本处理)。