我有这个Java
代码:
Connection conn = connectionProvider.getConnection();
statement = conn.prepareCall("execute procedure rm_set_coordinates(?,?,?)");
statement.setInt(1, userId);
statement.setString(2, String.valueOf(location.getLatitude()));
statement.setString(3, String.valueOf(location.getLongitude()));
statement.execute();
其中rm_set_coordinates
是Firebird
存储过程:
create or alter procedure RM_SET_COORDINATES (
PCAR_LOGIN integer,
PLAT varchar(20) = 0,
PLNG varchar(20) = 0)
returns (
ORESULT integer,
ORESULT_MSG varchar(500))
as
begin
update ref_car rc set rc.rm_last_connect_time='now',rc.rm_lat=:plat,rc.rm_lng=:PLNG where rc.id=:pcar_login;
oresult=1;
oresult_msg='';
suspend;
end
当我执行这个代码时,ref_car
表中的数据没有改变。但如果我将这一行添加到上面的代码:
statement.getInt(1);
返回oresult
输出参数的值,则正常,更新ref_car
表中的数据。
问题在于您在存储过程中使用了SUSPEND
。关键字SUSPEND
用于可选择的存储过程(生成多行数据的存储过程)。由于存储过程只生成一行,因此SUSPEND
是不必要的(也是原因)。
对于可选程序,Jaybird将您的execute procedure rm_set_coordinates(?,?,?)
转换为SELECT * FROM rm_set_coordinates(?,?,?)
。我不能100%确定Firebird存储过程的实现细节,但它看起来像是一个包含SUSPEND
的块,要么只在实际提取行时执行,要么在关闭或重用语句之前未提取行时,还原对上一个SUSPEND
的所有更改。
然而,最终的结果是:没有提取任何行,也没有更改。当执行可选存储过程(即:它包含SUSPEND
)时,Jaybird以不同于"正常"可执行存储过程的方式检索结果。
已知可执行存储过程只有一行(或没有一行)结果,因此执行时会立即检索这些值,并且可以使用getXXX()
方法检索结果。对于可选择的存储过程,结果像正常的ResultSet
一样被检索。对于可选择的存储过程,通常应使用executeQuery()
并处理返回的ResultSet
。由于实现伪影以及与旧版本的Firebird的兼容性(无法区分可选过程和可执行过程),因此也可以使用CallableStatement
的getXXX()
方法检索ResultSet
的第一行(或当前)的值。
TL;DR:卸下SUSPEND
。
披露:我是Jaybird 的开发人员之一