Spring Service层调用Oracle存储过程保证同一事务
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Spring Service层调用Oracle存储过程保证同一事务
在一个标记了@Transactional注解的Spring Service层bean方法里调用了一
个存储过程处理数据,后续还执行一系列的程序代码来处理数据,需要保证后面的程序代码报错后让存储过程插入更新的数据也回滚,即使用的数据库Connection为同一个,也就是说事务要是同一个。
经多次测试发现,通过dataSource获取Connection或者SessionFactory的方式获取Connection,都不是同一个connection,因为连接池返回的不是同一个接连。但通过DataSourceUtil工具获取的连接为同一个connection,因为它是将连接通过TreadLocal的方式绑定在线程本地变量里,使得在整个线程的过程中都使用的是同一个数据库连接,而事务是基于同一个数据库连接的。
例子:亲测可行!!!
存储过程如下:
create or replace procedure PRC_TEST(jkdmxx in varchar2,pclywid in number, flag out number) is
v_ErrorCode NUMBER;
v_ErrorTextVARCHAR2(2000);
begin
insert into T_JFRXX(JFR_ID,JFR_MC,DLYHMC,JFZH,DW_ID,ZT,CJSJ)
values(10000,'成功测试','成功测试
123','033432-180********',10135,'100',sysdate);
flag :=1;
exception
when others then
flag :=0;
v_ErrorCode := SQLCODE;
v_ErrorText := SUBSTR(SQLERRM, 1, 200);
rollback;
insert into T_JFRXX(JFR_ID,JFR_MC,DLYHMC,JFZH,DW_ID,ZT,CJSJ)
values(10001,'失败测试','失败测试
123','033432-180********',10135,'1',sysdate);
commit;
RAISE_APPLICATION_ERROR(-20001, '单机文件存储过程处理异常'); --抛出异常让程序捕获
end PRC_TEST;
注意:存储过程正常业务逻辑代码里,不能有显示的commit;
程序代码如下:
@Override
@Transactional(rollbackFor = Throwable.class, readOnly = false)
public void handleFmData(List
CallableStatementcstm = null;
try {
connection =
DataSourceUtils.getConnection(dataSource);
booleanisConnectionTransactional = DataSourceUtils.isConnectionTransactional(connection, dataSource);
System.out.println(isConnectionTransactional);
cstm = connection.prepareCall("{call
prc_test(?,?,?)}");
cstm = connection.prepareCall("{call
prc_test(?,?,?)}");
cstm.setString(1, Constant.JKXX_FMLXKPWJ_DSDJ);
cstm.setInt(2, 1);
cstm.registerOutParameter(3,
java.sql.Types.INTEGER);
cstm.executeUpdate();
Integer retValue = cstm.getInt(3);
System.out.println("存储过程返回值: " + retValue);
JfrxxjfrxxDB = jfrxxRep.findById(10000L);
BizException.throwWhenNull(jfrxxDB,"无法找到对象");//检查存储过程是否插入数据成功
//后续的程序逻辑代码
Jfrxxjfrxx = new Jfrxx();
jfrxx.setZt("1");
jfrxx.setCjsj(TimeUtils.getSystemDateTime());
jfrxx.setDlyhmc("后台代码");
jfrxx.setDwId(10135L);
jfrxx.setJfrMc("后台代码测试插入");
jfrxx.setJfzh("033532-180********");
jfrxxRep.save(jfrxx);
} catch (Exception e) {
logger.error(ExceptionUtils.getStackTrace(e));
throw new BizException(e);//只有这里抛出异常到事务方法外,才会回滚
} finally {
JdbcUtils.closeStatement(cstm);
DataSourceUtils.releaseConnection(connection, dataSource);
}
}