我已经在使用innodb引擎的表上成功创建插入前触发器,它通过在不存在的表上执行插入操作来“抛出”错误。问题是,当我尝试在生产服务器上运行数据库创建脚本时,它会失败,因为插入表不存在。但是,同样的脚本在我的工作站上运行良好,这让我认为存在导致创建脚本失败的MySQL配置设置。MySQL创建“插入前”触发失败并在触发器中引发错误
我的问题带来的问题是生产服务器是否正在编译触发器,而我的工作站是否(或在运行时编译)。在生产环境中,我希望在创建时编译SQL。
我已经在使用innodb引擎的表上成功创建插入前触发器,它通过在不存在的表上执行插入操作来“抛出”错误。问题是,当我尝试在生产服务器上运行数据库创建脚本时,它会失败,因为插入表不存在。但是,同样的脚本在我的工作站上运行良好,这让我认为存在导致创建脚本失败的MySQL配置设置。MySQL创建“插入前”触发失败并在触发器中引发错误
我的问题带来的问题是生产服务器是否正在编译触发器,而我的工作站是否(或在运行时编译)。在生产环境中,我希望在创建时编译SQL。
我的模拟触发错误的方法是给DECLARE
一个整数变量并在其中存储一个字符串。如果你有SQL_MODE = STRICT_ALL_TABLES
,这会产生一个错误。否则会引发警告。
use test;
drop table if exists foo;
create table foo (id serial primary key, bar varchar(10));
drop trigger if exists RaiseError;
delimiter //
create trigger RaiseError before insert on foo
for each row
begin
declare bar int;
if new.bar = 'boom' then
set bar = 'You cannot store that value!';
end if;
end //
delimiter ;
set sql_mode = strict_all_tables;
insert into foo (bar) values ('boom');
通知我叫我的本地变量一样的列酒吧,我想测试。这样变量的名称出现在错误消息中,与列相同:
错误1366(HY000):错误的整数值:'您不能存储该值!'列1'栏'栏
原来表名的长度导致了问题。这两个服务器版本来自不同的版本,服务器是先前版本(5.0 vs 5.1)。
至于在触发器中引发错误,我采取了一种不同的方法,但是根据MySQL如何处理创建触发器语句可能存在缺陷。如果触发语句在创建时被验证,那么这将失败。
一旦遇到错误(预期错误),我将设置一个会话变量(带@前缀的变量名),并显示错误消息。一旦设置了错误消息,我会插入到不存在的表Die中,以引发MySQL中的错误。
然后,应用程序捕获数据库错误并对错误会话变量执行查询。根据结果,我要么抛出一个异常与错误消息,数据库错误消息或让查询安静地失败,留下调用代码来处理失败的查询。
MySQL的触发器:
CREATE TRIGGER Error_Trigger
BEFORE INSERT ON Fubar
FOR EACH ROW
BEGIN
if DataIsBad then
set @Err = 'The data is fubared.';
insert into Die values (1);
end if;
END$$
应用端代码:
public function getDatabaseErrorMessage($AdminMessage = false){
if ($this->db->_error_number() != 0){
$AdminError = $this->db->_error_message();
$Query = $this->db->query("select @Err");
if ($Query){
$Error = $Query->row_array();
}
if (isset($Error["@Err"]) && $Error["@Err"] != ""){
$Error = $Error["@Err"];
$this->db->query("set @Err = ''");
} else {
if ($AdminMessage){
$Error = $AdminError;
} else {
return false;
}
}
throw new Exception($Error);
}
}