八月 21, 2023
摘要:在本教程中,您将学习如何在 PL/pgSQL 中捕获 PostgreSQL 异常。
目录
PL/pgSQL 异常子句简介
当代码块中发生错误时,PostgreSQL 将中止该块以及周围事务的执行。
要从错误中恢复,您可以使用begin...end
块中的exception
子句。
下面说明了exception
子句的语法:
<<label>>
declare
begin
statements;
exception
when condition [or condition...] then
handle_exception;
[when condition [or condition...] then
handle_exception;]
[when others then
handle_other_exceptions;
]
end;
怎么运行的。
- 首先,当
begin
和exception
之间发生错误时,PL/pgSQL 停止执行并将控制权传递给异常列表。 - 其次,PL/pgSQL 搜索第一个与发生错误相匹配的
condition
。 - 第三,如果匹配,则执行相应的
handle_exception
语句。PL/pgSQL 将控制权传递给end
关键字后面的语句。 - 最后,如果没有找到匹配项,错误就会传播出去,并且可以被包围块的
exception
子句捕获。如果该exception
子句外部没有包围的块,PL/pgSQL 将中止处理。
select
语句不返回行时,异常名称可以是no_data_found
,或者select
语句返回多行时,异常名称可以是too_many_rows
。有关异常名称的完整列表,请查看 PostgreSQL 文档。
也可以通过SQLSTATE
代码指定错误条件。例如,对于no_data_found
可指定P0002
,对于too_many_rows
可指定P0003
。
通常,您将捕获特定的异常并进行相应的处理。要处理没有在异常列表中指定的其他异常,可以使用when others then
子句。
处理异常示例
我们将使用示例数据库中的film
表进行演示。
1) 处理 no_data_found 异常的示例
以下示例会发出错误,因为 id 为 2000 的影片不存在。
do
$$
declare
rec record;
v_film_id int = 2000;
begin
-- select a film
select film_id, title
into strict rec
from film
where film_id = v_film_id;
end;
$$
language plpgsql;
输出:
ERROR: query returned no rows
CONTEXT: PL/pgSQL function inline_code_block line 6 at SQL statement
SQL state: P0002
以下示例使用exception
子句捕获no_data_found
异常并报告更有意义的消息:
do
$$
declare
rec record;
v_film_id int = 2000;
begin
-- select a film
select film_id, title
into strict rec
from film
where film_id = v_film_id;
-- catch exception
exception
when no_data_found then
raise exception 'film % not found', v_film_id;
end;
$$
language plpgsql;
输出:
ERROR: film 2000 not found
CONTEXT: PL/pgSQL function inline_code_block line 14 at RAISE
SQL state: P0001
2) 处理 too_many_rows 异常的示例
下面的例子说明了如何处理too_many_rows
异常:
do
$$
declare
rec record;
begin
-- select film
select film_id, title
into strict rec
from film
where title LIKE 'A%';
exception
when too_many_rows then
raise exception 'Search query returns too many rows';
end;
$$
language plpgsql;
输出:
ERROR: Search query returns too many rows
CONTEXT: PL/pgSQL function inline_code_block line 15 at RAISE
SQL state: P0001
在此示例中,发生too_many_rows
异常是因为该select into
语句返回多行,而它应该只返回一行。
3) 处理多个异常
以下示例说明了如何捕获多个异常:
do
$$
declare
rec record;
v_length int = 90;
begin
-- select a film
select film_id, title
into strict rec
from film
where length = v_length;
-- catch exception
exception
when sqlstate 'P0002' then
raise exception 'film with length % not found', v_length;
when sqlstate 'P0003' then
raise exception 'The with length % is not unique', v_length;
end;
$$
language plpgsql;
输出:
ERROR: The with length 90 is not unique
CONTEXT: PL/pgSQL function inline_code_block line 17 at RAISE
SQL state: P0001
4) 以 SQLSTATE 代码处理异常
以下示例与上面的示例相同,只是它使用的是SQLSTATE
代码而不是异常名称:
do
$$
declare
rec record;
v_length int = 30;
begin
-- select a film
select film_id, title
into strict rec
from film
where length = v_length;
-- catch exception
exception
when sqlstate 'P0002' then
raise exception 'film with length % not found', v_length;
when sqlstate 'P0003' then
raise exception 'The with length % is not unique', v_length;
end;
$$
language plpgsql;
输出:
ERROR: film with length 30 not found
CONTEXT: PL/pgSQL function inline_code_block line 15 at RAISE
SQL state: P0001
总结
使用begin...end
块中的exception
子句来捕获和处理异常。