Halo Tech

Halo数据库兼容MySQL存储过程之异常

引言

    众所周知,在高级编程语言中,可以在可能出错的代码外围添加类似try ... catch的方法捕获异常,用户可以添加自己想要的异常处理逻辑,从而保证系统的稳定运行。在各个数据库中,同样存在类似的功能,该功能用于存储过程中,可以保证存储过程的稳定运行,从而增强系统的健壮性。

    羲和(Halo)数据库从语法和功能两方面全面兼容MySQL数据库的异常处理功能,用户无需修改使用MySQL语法编写的异常处理代码,可直接在Halo数据库中进行创建及使用。

MySQL异常处理语法说明

    在MySQL存储过程中,使用异常处理的语法如下:

DECLARE handler_action HANDLERFOR condition_value [, condition_value] ...statementhandler_action: {CONTINUE| EXIT| UNDO}condition_value: {mysql_error_code| SQLSTATE [VALUE] sqlstate_value| condition_name| SQLWARNING| NOT FOUND| SQLEXCEPTION}

    上述语法可以为一种或多种异常条件确定一种异常处理方式,当这些异常条件中的某个异常条件发生时,指定的statement将被执行,statement可以是一个简单的SQL语句,也可以是一个begin ... end复合语句块。

    handler_action表示在异常发生,statement执行之后存储过程将要采取的动作,CONTINUE表示继续执行后续逻辑,EXIT表示退出声明该异常处理的begin ... end复合语句块,UNDO尚未实现。

    condition_value表示异常条件。

羲和(Halo)数据库兼容MySQL存储过程异常处理说明

1.兼容MySQL异常处理语法(declare ... handler)。

2.兼容MySQL异常处理语法中handler_action的CONTINUE, EXIT值。

3.兼容MySQL异常处理语法中condition_value的NOT FOUND,SQLEXCEPTION值。

羲和(Halo)数据库兼容MySQL存储过程异常处理测试

1.创建测试表t3并准备数据

create table t3(w char(1),x char(1),unique key(w));insert into t3 values('a', 'b');
Image

2.handler_action取值为CONTINUE时的测试

    情况1:在可能发生异常的同级begin ... end块中声明异常处理逻辑

    创建测试存储过程ptest_t3:

delimiter //create procedure ptest_t3()begin    declare continue handler for sqlexception        begin            select "execute ptest_t3 continue handler" as msg;        end;
    insert into t3 values('a', 'c');    insert into t3 values('b', 'c');end//delimiter ;
Image

    在测试存储过程ptest_t3中,声明了handler_action取值为CONTINUE的异常处理逻辑。因为测试表t3的w字段上有唯一索引,且表中w字段已有’a’值,当调用ptest_t3时,执行第一条insert语句会触发异常,从而执行异常处理逻辑,输出描述信息,至此,第一条insert处理完成。因为该异常的handler_action取值为CONTINUE,之后会继续执行第二条insert语句,该语句插入的值不会违反唯一键约束,不会触发异常,数据正常插入到测试表t3中。

    测试存储过程ptest_t3调用及结果如下:

call ptest_t3();select * from t3;
Image

    情况2:在可能发生异常的begin ... end块的外层声明异常处理逻辑

    删除表t3中的新增数据,重新创建测试存储过程ptest_t3:

delete from t3 where w='b';drop procedure if exists ptest_t3;delimiter //create procedure ptest_t3()begin    declare continue handler for sqlexception        begin            select "execute outer continue handler" as msg;        end;
    begin        insert into t3 values('a', 'c');        insert into t3 values('b', 'c');    end;     insert into t3 values('b', 'd');end//delimiter ;
Image

    在测试存储过程ptest_t3的外层begin ... end块中声明了handler_action取值为CONTINUE的异常处理逻辑。因为测试表t3的w字段上有唯一索引,且表中w字段已有’a’值,当调用ptest_t3时,执行内层begin ... end块中第一条insert语句会违反唯一键约束触发异常,从而执行外层begin ... end块异常处理逻辑,输出描述信息,至此,第一条insert处理完成。因为该异常的handler_action取值为CONTINUE,之后会继续执行内层begin ... end块的第二条insert语句,该语句插入的值不会违反唯一键约束,不会触发异常,数据正常插入到测试表t3中,至此,第二条insert处理完成,内层begin ... end块执行完成。之后继续执行外层begin ... end块下的insert语句,这条语句插入的数据会违反唯一键约束触发异常,从而又执行外层begin ... end块异常处理逻辑,输出描述信息。

    测试存储过程ptest_t3调用及结果如下:

call ptest_t3();select * from t3;
Image

3.handler_action取值为EXIT时的测试

    情况1:在可能发生异常的同级begin ... end块中声明异常处理逻辑

    删除表t3中的新增数据,重新创建测试存储过程ptest_t3:

delete from t3 where w='b';drop procedure if exists ptest_t3;delimiter //create procedure ptest_t3()begin    declare exit handler for sqlexception        begin            select "execute ptest_t3 exit handler" as msg;        end;
    insert into t3 values('a', 'c');    insert into t3 values('b', 'c');end//delimiter ;
Image

    在测试存储过程ptest_t3中,声明了handler_action取值为EXIT的异常处理逻辑。因为测试表t3的w字段上有唯一索引,且表中w字段已有’a’值,当调用ptest_t3时,执行第一条insert语句会触发异常,从而执行异常处理逻辑,输出描述信息,至此,第一条insert处理完成。因为该异常的handler_action取值为EXIT,之后会直接退出声明该异常处理的begin ... end块,不会执行第二条insert语句,所以测试表t3不会有新数据。

    测试存储过程ptest_t3调用及结果如下:

call ptest_t3();select * from t3;
Image

    情况2:在可能发生异常的begin ... end块的外层声明异常处理逻辑

    重新创建测试存储过程ptest_t3:

drop procedure if exists ptest_t3;delimiter //create procedure ptest_t3()begin    declare exit handler for sqlexception        begin            select "execute outer exit handler" as msg;        end;
    begin        insert into t3 values('a', 'c');        insert into t3 values('b', 'c');    end;
    insert into t3 values('b', 'd');end//delimiter ;
Image

    在测试存储过程ptest_t3的外层begin ... end块中声明了handler_action取值为EXIT的异常处理逻辑。因为测试表t3的w字段上有唯一索引,且表中w字段已有’a’值,当调用ptest_t3时,执行内层begin ... end块中第一条insert语句会违反唯一键约束触发异常,从而执行外层begin ... end块异常处理逻辑,输出描述信息,至此,第一条insert处理完成。因为该异常的handler_action取值为EXIT,所以直接从外层begin ... end块退出,存储过程调用完毕。

    测试存储过程ptest_t3调用及结果如下:

call ptest_t3();select * from t3;
Image

小结

    我们从不同客户的迁移案例中总结经验,并对羲和(Halo)数据库兼容MySQL的功能进行了大量测试,羲和(Halo)数据库对于MySQL有着很强的兼容性。在未来,我们将虚心接受大家提出的问题,经过不断的技术迭代,我们相信羲和(Halo)数据库将会越来越好。