调用含MERGE语句的Oracle存储过程时executeUpdate始终返回1求助
问题根因
你拿到的返回值永远为1的核心原因是 CallableStatement的executeUpdate()方法调用存储过程时,返回值仅表示存储过程是否执行成功,并非存储过程内部MERGE语句的实际影响行数。Oracle存储过程默认不会将内部DML的行数透传给JDBC接口,你当前拿到的1是存储过程执行成功的标识,和MERGE是否插入数据无关。
解决方案
第一步:修改存储过程,新增OUT参数返回影响行数
同时建议移除存储过程内部的COMMIT,事务控制交给上层Java代码更合理,避免事务边界混乱。
PROCEDURE INSERT_USER_PREFERENCES( owner_id_var varchar2, stripeid_var varchar2, type_var varchar2, metadata_var CLOB, -- 新增OUT参数返回影响行数 affect_rows OUT NUMBER ) AS BEGIN MERGE INTO CXO_USER_PREFERENCES d USING(SELECT stripeid_var id FROM dual) s ON (d.stripe_id = s.id) WHEN NOT MATCHED THEN INSERT (OWNER_ID, STRIPE_ID, PREF_TYPE, METADATA, CREATED_DATE ) VALUES(owner_id_var, stripeid_var, type_var, metadata_var, CURRENT_TIMESTAMP); -- 获取MERGE语句实际影响行数 affect_rows := SQL%ROWCOUNT; -- 建议移除该行COMMIT,交由Java层控制事务 -- COMMIT; END INSERT_USER_PREFERENCES;
第二步:修改Java调用逻辑,读取OUT参数值
不要使用executeUpdate()的返回值,改为读取存储过程返回的OUT参数即可拿到真实影响行数。
try (CallableStatement stmt = connection.prepareCall(CREATE_USER_PREF_SQL)) { SQLParameterMapper sqlParamMapper = new SQLParameterMapper(CREATE_USER_PREF_SQL); sqlParamMapper.setString(stmt, ":ownerId", userName); sqlParamMapper.setCharacterStream(stmt, ":metadata", reader, metadata.length()); sqlParamMapper.setString(stmt, ":stripeId", stripeId); sqlParamMapper.setString(stmt, ":type", userPreference.getType()); // 注册OUT参数,注意参数名和存储过程定义的OUT参数名对应 stmt.registerOutParameter(":affect_rows", Types.NUMERIC); // 调用存储过程 stmt.execute(); // 读取真实影响行数 int value = stmt.getInt(":affect_rows"); return value; } catch (SQLException e) { // 存储过程执行出错会直接抛出异常,符合预期 throw e; }
内容的提问来源于stack exchange,提问作者Harish Dalmia
相关产品推荐
相关产品推荐

