SQLServer 的存储过程与java交互
一、 存储过程简介
Sql Server的存储过程是一个被命名的存储在服务器上的Transacation-Sql语句集合,是封装重复性工作的一种方法,它支持用户声明的变量、条件执行和其他强大的编程功能。
存储过程相对于其他的数据库访问方法有以下的优点:
(1)重复使用。存储过程可以重复使用,从而可以减少数据库开发人员的工作量。
(2)提高性能。存储过程在创建的时候就进行了编译,将来使用的时候不用再重新编译。一般的SQL语句每执行一次就需要编译一次,所以使用存储过程提高了效率。
(3)减少网络流量。存储过程位于服务器上,调用的时候只需要传递存储过程的名称以及参数就可以了,因此降低了网络传输的数据量。
(4)安全性。参数化的存储过程可以防止SQL注入式的攻击,而且可以将Grant、Deny以及Revoke权限应用于存储过程。
存储过程一共分为了三类:用户定义的存储过程、扩展存储过程以及系统存储过程。
其中,用户定义的存储过程又分为Transaction-SQL和CLR两种类型。
Transaction-SQL 存储过程是指保存的Transaction-SQL语句集合,可以接受和返回用户提供的参数。
CLR存储过程是指对.Net Framework公共语言运行时(CLR)方法的引用,可以接受和返回用户提供的参数。他们在.Net Framework程序集中是作为类的公共静态方法实现的。(本文就不作介绍了)
二、先建一个测试用的表 (很基础的代码有点基础是可以看懂的)
--创建测试books表 create table books (book_id int identity(1,1) primary key,book_name varchar(20),book_price float,book_auth varchar(10) ); --插入测试数据 insert into books (book_name,book_price,book_auth)values('论语',25.6,'孔子'),('天龙八部',25.6,'金庸'),('雪山飞狐',32.7,'金庸'),('平凡的世界',35.8,'路遥'),('史记',54.8,'司马迁');
三、创建无参存储过程有写返回参数(返回结果集,至于为什么不使用游标返回,而是直接返回下面有介绍)
sqlserver 创建存储过程:
if (exists (select * from sys.objects where name = 'getAllBooks'))--判断是否存在存储过程drop proc getAllBooks -- 删除 go create procedure getAllBooks(@rowcount INT OUTPUT) -- 创建存储过程 as begin select * from books; SET @rowcount=@@rowcount end; go --调用,执行存储过程 DECLARE @count INT EXECUTE getAllBooks @count OUTPUT PRINT @count
java 代码(使用jdbcTemplate获取结果集)
public String StorageInfo(){String param2Value = (String) jdbcTemplate.execute(new CallableStatementCreator() {public CallableStatement createCallableStatement(Connection con) throws SQLException {String storedProc = "{CALL getAllBooks(?)}";// 调用的sqlCallableStatement cs = con.prepareCall(storedProc); // cs.setInt(1, 2);// 设置输入参数的值 // cs.setString(2, "99");// 设置输入参数的值cs.registerOutParameter(1, Types.JAVA_OBJECT);// 注册输出参数的类型return cs;}}, new CallableStatementCallback() {public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {cs.execute();//ResultSet rs = (ResultSet) cs.getObject(2);// 获取游标一行的值ResultSet rs = cs.getResultSet(); // System.out.println("CallableStatementCallback-------------:"+cs);while(rs.next()){int id = rs.getInt(1);String book_name = rs.getString(2);String book_auth = rs.getString(4);System.out.println("id:"+id+" 书名:"+book_name+" 作者:"+book_auth);}return null;// 获取输出参数的值 }});System.out.println("天天-------------:"+param2Value);return param2Value;}
四、创建有参存储过程没写返回参数(注意其中参数的区别,这个没有写返回out,sqlserver会自动返回)
sqlserver 创建有参存储过程
--2.创建有参存储过程 if exists(select * from sysobjects where name='getAllBooks') drop proc getAllBooks go --创建存储过程输入参数。 create proc getAllBooks @startId varchar(50) as begin(select * from books where book_id =@startId); end go declare @back varchar(2000) exec getAllBooks 2
java 实现 注意:没有注册输出参数
public String StorageInfo(){String param2Value = (String) jdbcTemplate.execute(new CallableStatementCreator() {public CallableStatement createCallableStatement(Connection con) throws SQLException {String storedProc = "{CALL getAllBooks(?)}";// 调用的sqlCallableStatement cs = con.prepareCall(storedProc);cs.setInt(1, 2);// 设置输入参数的值 // cs.setString(2, "99");// 设置输入参数的值 // cs.registerOutParameter(2, Types.JAVA_OBJECT);// 注册输出参数的类型return cs;}}, new CallableStatementCallback() {public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {cs.execute();//ResultSet rs = (ResultSet) cs.getObject(2);// 获取游标一行的值ResultSet rs = cs.getResultSet(); // System.out.println("CallableStatementCallback-------------:"+cs);while(rs.next()){int id = rs.getInt(1);String book_name = rs.getString(2);String book_auth = rs.getString(4);System.out.println("id:"+id+" 书名:"+book_name+" 作者:"+book_auth);}return null;// 获取输出参数的值 }});System.out.println("天天-------------:"+param2Value);return param2Value;}
五、创建有参返回单个属性值
--2.创建有参存储过程 if exists(select * from sysobjects where name='getAllBooks') drop proc getAllBooks go --创建存储过程输入参数。 create proc getAllBooks @startId varchar(50), @data nvarchar(100) output as begin set @data = (select book_name from books where book_id =@startId);end go declare @back varchar(2000) exec getAllBooks 2 ,@back output select @back dat
java 实现代码
public String StorageInfo(){String param2Value = (String) jdbcTemplate.execute(new CallableStatementCreator() {public CallableStatement createCallableStatement(Connection con) throws SQLException {String storedProc = "{CALL getAllBooks(?,?)}";// 调用的sqlCallableStatement cs = con.prepareCall(storedProc);cs.setInt(1, 2);// 设置输入参数的值 // cs.setString(2, "99");// 设置输入参数的值cs.registerOutParameter(2, Types.VARCHAR);// 注册输出参数的类型return cs;}}, new CallableStatementCallback() {public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {cs.execute();//ResultSet rs = (ResultSet) cs.getObject(2);// 获取游标一行的值ResultSet rs = cs.getResultSet();System.out.println("CallableStatementCallback-------------:"+cs.getString(2)); // while(rs.next()){ // int id = rs.getInt(1); // String book_name = rs.getString(2); // String book_auth = rs.getString(4); // System.out.println("id:"+id+" 书名:"+book_name+" 作者:"+book_auth); // }return null;// 获取输出参数的值 }});System.out.println("天天-------------:"+param2Value);return param2Value;}
六、下面来说说sqlserver 为什么不能返回游标
这是我的代码
--2.创建有参存储过程 游标接收结果集if exists(select * from sysobjects where name='proc_find_stu') drop proc proc_find_stu go --创建存储过程输入参数。 create proc proc_find_stu @startId varchar(50), @data CURSOR VARYING OUTPUT as begin-- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- print @overTimeHour; -- 1. 声明游标: DECLARE CURSOR_PriceChangeRecord SET @data = CURSOR FORWARD_ONLY STATIC FOR (select * from books where book_id =@startId);OPEN @data return 1; end go declare @back CURSOR exec proc_find_stu 2,@back; select @back data
最开始头儿给了一个在oracle上可以直接跑的存储过程,在java程序里直接用jdbc来调用非常方便,没什么问题。之后便是狂找资料,把oracle上用PL/SQL写的存储过程改写成sqlserver上用Transact-SQL写的存储过程,改阿改,终于,在sqlserver的查询分析器上可以执行了,本以为已经做到这一步了,在jdbc里直接调用还不是小菜一碟,没想到呀,问题来了。
头儿给的这个存储过程有一个输出参数,是cursor(游标)型的,在jdbc里要用registerOutParameter这个方法在执行存储过程之前注册一下输出参数类型, 对于oracle的jdbc驱动这个问题很好办。直接写registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);就OK了,看到oracle.jdbc.OracleTypes.CURSOR了吧,oracle正不错,直接就给你提供了一个表示游标型的整型常量。整个调用过程如下:
CallableStatement proc = null;
proc = conn.prepareCall("{call PROC_FWMA_DATAARCHIVE}");
proc.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);
proc.execute();
可microsoft呢,根本没有在它的jdbc驱动里提供类似的这样一个整型常量(尽管sqlserver里的存储过程是支持游标类型的输出参数的),用标准jdbc里的数据类型Types.other也没有,以运行,就抛异常了,什么mircosoft jdbc 不支持这样的数据类型。咋办呢,到处查资料呀,各种试建立临时表等等之类然而却没啥用,最后想看看有没有前辈碰到过这样的问题,可是怎么碰到这种问题的人似乎很少呢,找了半天,终于看到外国人的论坛上有人提出和我一样的问题,结果答案很打击人,说是microsoft的jdbc就是不支持。可是这个输出的结果是很重要的,那有没有其他解决方法呢?再查sqlserver的联机帮助,看到sqlserver的存储过程还支持直接返回结果集,只要在存储过程里写select就可以了,哈哈,些个简单的存储过程,没有输出参数。再修改刚才段代码为
CallableStatement proc = null;
proc = conn.prepareCall("{call PROC_FWMA_DATAARCHIVE}");
ResultSet rs = null;
rs = proc.getResultSet();
很好,结果集就拿到了。问题解决了?NO,试验用的是简单的存储过程,再用正式的那个复杂的带事务操作的存储过程,jdbc又傻了,如果执行存储过程用的是execute(),它就只返回出结果集,而不能做存储过程中的insert delete操作,如果用executeUpdate()执行,结果集就返回不出来了。
在这个问题上整整卡了一天,后来不知道怎么想了想,突然发现在存储过程中,我把要返回结果集的那句select是放在了事务操作的外面,会不会是这里有问题呢?马上动手,把select塞到事务里面,再运行,终于OK了。
猜测可能是如果将select放在事务外的话,它和事务是同级别的,如果用execute()执行的话,就只做了select,不做事务了。当然这只是猜测了,真的要弄明白,恐怕要写email到微软去问了,英语太差,就不丢人现眼了。哪位大牛帮忙问问?
示例代码:https://gitee.com/xdymemory00/sqlserver-CunChuGuoChengYujavaJiaoHu.git
转载于:https://www.cnblogs.com/memoryXudy/p/7776910.html
SQLServer 的存储过程与java交互相关推荐
- sqlserver 创建存储过程及基本语法
本文记录sqlserver 创建存储过程及基本语法的讲解,附上作者实现功能的实例 背景:作者的task是需要两个数据库之间进行数据迁移,本可以用java程序来实现,后面觉得可以学习下存储过程,故采用这 ...
- 把sqlserver中存储过程改写到oracle中
一同学叫我帮忙改存储过程sqlserver----->oralce数据中: sqlserver中存储过程: SET QUOTED_IDENTIFIER ON GO SET ANSI_N ...
- SqlServer中存储过程中将Exec的执行结果赋值给变量输出
原文 SqlServer中存储过程中将Exec的执行结果赋值给变量输出 背景: 遇到这样一种情况:动态向存储过程中传入表名和表的某些属性(这里用到的是主键ID),然后利用这两个变量查出一条数据的某些字 ...
- java实现报表_用存储过程和 JAVA 写报表数据源有什么弊端?
用存储过程和 JAVA 写报表数据源有什么弊端?跟着小编一起来一看一下吧! 我们在报表开发中经常会使用存储过程准备数据,存储过程支持分步计算,可以实现非常复杂的计算逻辑,为报表开发带来便利.所以,报表 ...
- java使用xml存储数据_用存储过程和 JAVA 写报表数据源有什么弊端?
用存储过程和 JAVA 写报表数据源有什么弊端?跟着小编一起来一看一下吧! 我们在报表开发中经常会使用存储过程准备数据,存储过程支持分步计算,可以实现非常复杂的计算逻辑,为报表开发带来便利.所以,报表 ...
- blazeds调用java_Flex使用Blazeds与Java交互及自定义对象转换详解(转)
一.建立Flex与Java交互的工程. 本文中讲到的交互是利用Blazeds的,因为这个是免费的,呵呵,我是穷人. 首先就是去下载Blazeds的压缩包,这个可以从官网或者CSDN.JavaEye上下 ...
- java元数据是什么_用存储过程和 JAVA 写报表数据源有什么弊端?
用存储过程和 JAVA 写报表数据源有什么弊端?跟着小编一起来一看一下吧! 我们在报表开发中经常会使用存储过程准备数据,存储过程支持分步计算,可以实现非常复杂的计算逻辑,为报表开发带来便利.所以,报表 ...
- flex java oracle_Flex使用Blazeds与Java交互及自定义对象转换详解-DATAGRID读取ORACLE数据...
一.建立Flex与Java交互的工程. 本文中讲到的交互是利用Blazeds的,因为这个是免费的,呵呵,我是穷人. 首先就是去下载Blazeds的压缩包,这个可以从官网或者CSDN.JavaEye上下 ...
- A Scala Tutorial for Java programmers之(一)Scala入门:Scala例子,以及如何与Java交互
本文为初学Scala的Java开发者提供了一个Scala例子(Hello world),并对Scala与Java交互的情况作了一些大致的介绍. AD: 本文源自Michel Schinz和Philip ...
最新文章
- Nagios的安装和基本配置(四:调试验证 错误总结)
- HTTP详解(1)-工作原理【转】
- sqlldr,将数据批量导入Oracle数据库
- React-状态提升
- POJ-3281-Dining(求一对二最大匹配数/最大流)
- “约见”面试官系列之常见面试题第十七篇之实现深拷贝(建议收藏)
- 计算机模拟量与数字量的转换,在S7-1200 CPU中,如何实现模拟量数值与工程量数值之间的转换?...
- 再见,付费录屏软件!我用70行Python代码打造免费版!
- 一加7T Pro曝光:10月10日发布
- 【转】linux图形界面编程基本知识
- mysql java事物回滚吗_为什么 MySQL 回滚事务也会导致 ibd 文件增大?
- 20211205:力扣第270场周赛(上)
- html5从基础到入门,Html5从入门到精通系列2:Html5基础
- 浏览器插件之ActiveX开发(三)
- 小白学习一eNSP华为模拟器(5)利用三层交换机实现VLAN间路由
- Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean
- mysql 按照年龄段分组查询
- Linux软件包管理工具-yum
- 智能分层、满足更高工作负载,亚马逊云科技加速云端存储服务创新
- 深度揭秘:到底什么是“授时”
热门文章
- 基于mint-ui的城市选择3级联动
- Github|类别不平衡学习资源(上)
- java 图片阴影_Java 为 PPT 中的图形添加阴影效果
- js保留两位小数的函数_使用率低但功能强大的6个Excel函数公式应用技巧解读!...
- git语言包安装_Git分布式版本管理系统快速入门指南
- 自然语言处理的一些链接
- django ORM创建数据库方法
- 【JZOJ4819】【NOIP2016提高A组模拟10.15】算循环
- 每个 Linux 用户都应该知道的命令行技巧
- 字符串拼接成insert语句[简单记录]