从 MySQL 触发器调用 PHP 脚本
Posted
技术标签:
【中文标题】从 MySQL 触发器调用 PHP 脚本【英文标题】:Invoking a PHP script from a MySQL trigger 【发布时间】:2010-11-30 20:13:10 【问题描述】:当记录插入 mysql 数据库表时,有什么方法可以调用 php 页面/函数?我们无法控制记录插入过程。有没有可以回调PHP脚本的触发机制?
【问题讨论】:
也许这对你有帮助:***.com/questions/40025369/… 【参考方案1】:触发器在 MySQL 服务器上执行,而不是在 PHP 上执行(即使它们都在同一台机器上)。
所以,我想说这不太可能——至少不是简单的。
不过,考虑到this entry from the MySQL FAQ on Triggers:
23.5.11:触发器可以通过 UDF 调用外部应用程序吗?
是的。例如,触发器可以 调用此处可用的
sys_exec()
UDF: https://github.com/mysqludf/lib_mysqludf_sys#readme
因此,可能有一种方法可以通过 UDF 函数启动 php 可执行文件/脚本。不是那么容易,但似乎有可能。 ;-)
【讨论】:
或者你他可以叫 curl? 如果 php 和/或脚本不在同一个物理服务器上,它也可能是一个解决方案,是的。 Martin 的技巧很酷……但是以这种方式调用 PHP 并不是一个好的设计选择。你应该重新考虑它 对此有什么更好的设计选择?每隔一段时间检查一次 cron 脚本之类的东西? @Stef 我很欣赏你的观点。你能提供更好的选择吗?【参考方案2】:我和一个朋友想出了如何调用 Bernardo Damele 的 sys_eval UDF,但该解决方案并不像我想要的那样优雅。这是我们所做的:
-
由于我们使用的是 Windows,我们必须使用 Roland Bouman's instructions 为 Windows 编译 UDF 库并将它们安装在我们的 MySQL 服务器上。
我们创建了一个调用 sys_eval 的存储过程。
我们创建了一个调用存储过程的触发器。
存储过程代码:
DELIMITER $$
CREATE PROCEDURE udfwrapper_sp
(p1 DOUBLE,
p2 DOUBLE,
p3 BIGINT)
BEGIN
DECLARE cmd CHAR(255);
DECLARE result CHAR(255);
SET cmd = CONCAT('C:/xampp/php/php.exe -f "C:/xampp/htdocs/phpFile.php" ', p1, ' ', p2, ' ', p3);
SET result = sys_eval(cmd);
END$$;
触发码:
CREATE TRIGGER udfwrapper_trigger AFTER INSERT ON sometable
FOR EACH ROW
CALL udfwrapper_sp(NEW.Column1, NEW.Column2, NEW.Column3);
我对存储过程并不感到兴奋,我不知道它是否会产生额外的开销,但它确实有效。每次将一行添加到某个表时,触发器就会触发。
【讨论】:
【参考方案3】:从数据库触发器调用 PHP 代码应该被认为是一种非常糟糕的编程习惯。如果您将使用这种“疯狂”的技巧解释您尝试解决的任务,我们可能会提供一个令人满意的解决方案。
2014 年 3 月 19 日添加:
我应该早点添加一些推理,但现在才找到时间这样做。感谢@cmc 的重要评论。因此,PHP 触发器为您的应用程序添加了以下复杂性:
正如@Johan 所说,为应用程序添加了一定程度的安全问题(外部 PHP 脚本调用、权限设置、可能是 SELinux 设置等)。
为您的应用程序增加了额外的复杂性(要了解数据库的工作原理,您现在需要了解 SQL 和 PHP,而不仅仅是 SQL)并且您还必须调试 PHP,而不仅仅是 SQL。
1234563 .添加额外的性能分析点。每个 PHP 调用都很昂贵,因为您需要启动解释器、将脚本编译为字节码、执行它等。因此,涉及此触发器的每个查询都会执行得更慢。有时很难隔离查询性能问题,因为 EXPLAIN 没有告诉您任何有关由于触发例程性能而导致查询变慢的信息。而且我不确定触发时间是如何转储到慢查询日志中的。
为应用程序测试添加了一些问题。 SQL 可以很容易地测试。但是要测试 SQL + PHP 触发器,您将不得不运用一些技巧。
【讨论】:
为什么?看起来它可能非常实用。例如,一个 php 脚本插入到远程 db 服务器上,服务器可以启动一个本地 php 脚本在该机器上执行某些操作。 我不认为这是一种“非常糟糕的编程习惯”......这只是一种非常规的方式。在我的情况下,我需要从 MySQL->PHP->javascript(使用 html5 网络套接字)一路“实时”响应。由于 ws 服务器和 web 服务器运行在不同的端口,我没有其他“简单”的方法来实现它。 (并且......)每秒查询数据库对我来说似乎不切实际,因为数据不会每秒都发生变化(它可能不会在几个小时内改变)。 一个用例——当触发事件必须做一些 MYSQL 中不可用的处理时——比如 json 解析/现实世界很混乱:D 在没有任何解释的情况下将某些东西称为“坏”和“疯狂”而投反对票。 @Johan “内联网并不比互联网上的东西更安全” “员工不可信” “大多数犯罪都发生在工作内部” 这些都是过度概括,当然并不总是适用。所以正确的答案是“确保你采取预防措施,如果你尝试这样的黑客攻击有充分的理由”,而不是“这总是一个坏主意”。【参考方案4】:我正在考虑这个确切的问题,因为我不希望 php 脚本必须不断地轮询数据库。轮询需要在某个地方进行,内存可能是最好的。因此,如果触发器可以以某种方式将信息放入 memcache 之类的东西中,那么 php 可以进行轮询,这将整体上不那么密集。只需要一个mysql使用memcache的方法。也许进入具有特定用户 ID 的预定义变量。一旦检索到数据,php 可以重置 var,直到 db 再次设置它。不过不确定时间问题。也许是第二个变量来存储上一个选择的键。
【讨论】:
【参考方案5】:我发现了这个:
http://forums.mysql.com/read.php?99,170973,257815#msg-257815
DELIMITER $$
CREATE TRIGGER tg1 AFTER INSERT ON `test`
FOR EACH ROW
BEGIN
\! echo "php /foo.php" >> /tmp/yourlog.txt
END $$
DELIMITER ;
【讨论】:
\! command : 只执行一次(在 CREATE TRIGGER 上)。它不会在插入时执行。【参考方案6】:为了从数据库中获取通知,我使用 websocket 编写了一个命令行脚本,以每秒检查最新更新的时间戳。这在服务器上作为无限循环运行。如果发生更改,所有连接的客户端都将收到通知。
【讨论】:
这有轮询的所有问题:要么你轮询太少,导致延迟,要么你轮询太频繁,并且从所有轮询中产生过多的负载【参考方案7】:如果您的 MySQL 中有事务日志,则可以创建触发器以创建日志实例。 cronjob 可以监视此日志并根据触发器创建的事件调用 php 脚本。也就是说,如果您绝对无法控制插入。
【讨论】:
【参考方案8】:我不知道这是否可能,但我总是想象自己能够使用 MySQL 中的 CSV 存储引擎来做到这一点。我不知道这个引擎的细节: http://dev.mysql.com/doc/refman/5.7/en/csv-storage-engine.html 但您可以查看它并在您的操作系统中有一个文件观察器,如果文件被修改,它会触发 PHP 调用。
【讨论】:
【参考方案9】:cronjob 可以监控此日志,并根据触发器创建的事件调用 php 脚本。也就是说,如果您绝对无法控制插入。如果您的 MySQL 中有事务日志,则可以创建触发器以创建日志实例。
【讨论】:
【参考方案10】:尽可能远离存储过程。它们很难维护,而且是非常古老的东西;)
【讨论】:
如果您知道自己在做什么,那么维护起来并不难:P 他们也可以为您节省大量时间 这真是垃圾。 SP 确实存在问题,在不熟练的手中确实可能很糟糕,但如果使用得当,它们效率很高,并且确实是逻辑一致性的最佳选择 存储过程是唯一已知的对数据库服务器上的数据库事件做出反应的方式,任何人都可以逃避它吗? Java 开发者:我应该在 Oracle 上使用存储过程吗?答:你必须! || .NET 开发人员:我应该在 M. SQL Server 上使用存储过程吗???答:必须!!! || PHP 开发者:不要使用存储过程,它们没用,老旧,不是 OOP || PHP 开发人员:为什么不再有人想将 PHP 用于完整的企业解决方案??? ||我......我的头撞在了墙上:-(以上是关于从 MySQL 触发器调用 PHP 脚本的主要内容,如果未能解决你的问题,请参考以下文章