2010-09-03 158 views
0

我已经在使用innodb引擎的表上成功创建插入前触发器,它通过在不存在的表上执行插入操作来“抛出”错误。问题是,当我尝试在生产服务器上运行数据库创建脚本时,它会失败,因为插入表不存在。但是,同样的脚本在我的工作站上运行良好,这让我认为存在导致创建脚本失败的MySQL配置设置。MySQL创建“插入前”触发失败并在触发器中引发错误

我的问题带来的问题是生产服务器是否正在编译触发器,而我的工作站是否(或在运行时编译)。在生产环境中,我希望在创建时编译SQL。

回答

0

我的模拟触发错误的方法是给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'栏'栏

0

原来表名的长度导致了问题。这两个服务器版本来自不同的版本,服务器是先前版本(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); 
    } 
}