数据回填
RETURNING ... INTO 在执行写入的同时返回字段值,无需再执行 SELECT。INSERT 返回插入后的值,UPDATE 返回更新后的值,DELETE 返回删除前的值。
在 dbVisitor 中,使用 JdbcTemplate.call 执行 BEGIN ... END; 匿名块,通过 OUT 参数获取返回值,不按 SELECT 处理。匿名块无需预先创建存储过程。
插入后返回字段
以下示例依次使用同一张表:
CREATE TABLE user_info (
id NUMBER(10) PRIMARY KEY,
name VARCHAR2(100),
age NUMBER(3)
);
插入时由数据库将名字 转为大写,并返回实际写入的名字和年龄:
import java.util.Map;
import net.hasor.dbvisitor.jdbc.core.JdbcTemplate;
JdbcTemplate jdbc = new JdbcTemplate(dataSource);
Map<String, Object> result = jdbc.call("""
BEGIN
INSERT INTO user_info (id, name, age)
VALUES (#{id}, UPPER(#{name}), #{age})
RETURNING name, age INTO #{savedName,mode=out,jdbcType=varchar},
#{savedAge,mode=out,jdbcType=integer};
END;
""", Map.of("id", 918101, "name", "alice", "age", 20));
String name = (String) result.get("savedName"); // ALICE
Integer age = (Integer) result.get("savedAge"); // 20
mode=out 声明输出参数,jdbcType 指定接收类型。返回 Map 的键就是输出参数名;需要写回实体时,将值赋给对应属性即可。
更新后返回字段
将年龄加一,返回更新后的年龄。通过 SQL%ROWCOUNT 同时取得实际更新条数:
Map<String, Object> result = jdbc.call("""
BEGIN
UPDATE user_info SET age = age + 1 WHERE id = #{id}
RETURNING age INTO #{savedAge,mode=out,jdbcType=integer};
#{rows,mode=out,jdbcType=integer} := SQL%ROWCOUNT;
END;
""", Map.of("id", 918101));
if ((Integer) result.get("rows") == 1) {
Integer age = (Integer) result.get("savedAge"); // 21
}
删除时返回字段
删除记录,同时取得被删除的名字:
Map<String, Object> result = jdbc.call("""
BEGIN
DELETE FROM user_info WHERE id = #{id}
RETURNING name INTO #{deletedName,mode=out,jdbcType=varchar};
#{rows,mode=out,jdbcType=integer} := SQL%ROWCOUNT;
END;
""", Map.of("id", 918101));
if ((Integer) result.get("rows") == 1) {
String name = (String) result.get("deletedName"); // ALICE
}
注意
- 上例使用单值输出参数,更新和删除通过主键限定为一条记录,不适用于多行返回。
- 未匹配记录时,不读取返回字段;先检查
rows是否为1。
输出参数的通用用法见存储过程调用;自增主键的自动回填见主键生成。语法说明见 Oracle RETURNING INTO。