如何在CodeIgniter模型中使用MySQL事件调度器?问题解决
看起来你遇到的问题是MySQL事件创建语句在CMD里正常执行,但在CodeIgniter模型里没效果,甚至没报错。我帮你梳理几个关键原因和对应的解决办法:
1. 最容易忽略的:你的模型代码根本没执行查询!
看你贴的模型代码片段,try块里只定义了$sql变量,但没有调用CodeIgniter的数据库查询方法去执行这条SQL!你需要添加执行语句:
public function insert_credit_points_data($email){ try{ $sql = "CREATE EVENT ecp ON SCHEDULE EVERY 1 MINUTE STARTS NOW() DO BEGIN INSERT INTO emp_leave_balance (balance, date_from, ...) VALUES (...); END"; // 关键:执行SQL $this->db->query($sql); // 可以加个判断,确认执行结果 if ($this->db->affected_rows() > 0) { return true; } else { log_message('error', 'Event creation failed'); return false; } } catch (Exception $e) { log_message('error', $e->getMessage()); return false; } }
先补上这一步,再看是否生效。
2. DELIMITER $$是MySQL客户端命令,不是SQL语句!
你写的DELIMITER $$是给MySQL命令行工具(比如CMD里的mysql)用的,用来临时改变语句分隔符,MySQL服务器本身并不认识这个命令。所以直接在CI里执行包含DELIMITER的SQL会导致语法错误(虽然你说没报错,但可能CI的错误日志没开启)。
解决办法: 去掉DELIMITER $$和结尾的$$,直接写标准的CREATE EVENT语句:
CREATE EVENT ecp ON SCHEDULE EVERY 1 MINUTE STARTS NOW() DO BEGIN INSERT INTO emp_leave_balance (balance, date_from, email_address) VALUES (/* 你的值 */); -- 如果有多个SQL语句,直接用;分隔就行,BEGIN/END块会处理 END
3. CodeIgniter默认禁止多语句查询
因为安全原因,CI的数据库驱动默认不允许执行包含多个语句的SQL(比如BEGIN/END里的复合语句)。如果你的事件里有多个SQL语句,需要开启多语句支持:
针对MySQLi驱动: 在application/config/database.php里找到你的数据库配置,添加:
$db['default']['allow_multiple_statements'] = TRUE;
⚠️ 注意:开启这个选项会增加SQL注入风险,一定要确保你的SQL语句没有用户输入的变量,或者已经做了严格的参数绑定!
4. 数据库用户权限问题
创建MySQL事件需要EVENT权限,可能你CMD里用的数据库用户有这个权限,但CI配置的用户没有。
解决办法: 给CI的数据库用户授权:
GRANT EVENT ON `your_database_name`.* TO 'ci_db_user'@'localhost'; FLUSH PRIVILEGES;
替换your_database_name和ci_db_user为你的实际数据库名和用户名。
5. MySQL事件调度器是否开启
即使你创建了事件,如果MySQL的事件调度器是关闭的,事件也不会执行。
检查方法: 在CMD里执行:
SHOW VARIABLES LIKE 'event_scheduler';
如果结果是OFF,需要开启:
- 临时开启(重启MySQL后失效):
SET GLOBAL event_scheduler = ON; - 永久开启:在MySQL配置文件(my.cnf或my.ini)里添加
event_scheduler=ON,然后重启MySQL服务。
额外提醒:你真的需要定时事件吗?
看你的描述,需求是“向emp_leave_balance表中所有唯一的email_address插入数据”,如果这是一次性操作,根本不需要创建定时事件!直接用INSERT ... SELECT语句一次性插入所有唯一邮箱的数据就行:
INSERT INTO emp_leave_balance (balance, date_from, email_address) SELECT 0, NOW(), DISTINCT email_address FROM `your_source_table`;
这条语句在CI里执行完全没问题,不需要处理事件的各种问题,更简单安全。
内容的提问来源于stack exchange,提问作者Castling

