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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/428625.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[译]Javascript中的闭包(closures)

本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?vPMsVM7rjupU&listPL6n9fhu94yhUA99nOsJkKXBqokT3MBK0b 本次视频中我们将通过例子来理解Javascript中的闭包(closure) 什么是闭包(closure)? 一个闭包就是一个在…

二、PyCharm 创建Django 第一个项目

PyCharm 下创建Django项目 File->New Project->Django 目录说明: dj: 项目的容器。manage.py: 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。dj/__init__.py: 一个空文件,告诉 Python 该目录是一个 Python 包。dj/…

linux last failed login表示什么意思_Linux用户

Linux的用户在登录(login)之后,就带有一个用户身份(user ID, UID)和一个组身份(group ID, GID)。在Linux文件管理背景知识中,我们又看到,每个文件又有九位的权限说明,用来指明该文件允许哪些用户执行哪些操作(读、写或者执行)。(参…

CSS3详解:transform、transition

CSS3 transform是什么? transform的含义是:改变,使…变形;转换 CSS3 transform都有哪些常用属性? transform的属性包括:rotate() / skew() / scale() / translate(,) ,分别还有x、y之分&#xf…

D. Flowers

D. Flowers 一个简单线性dp#include <bits/stdc.h> using namespace std; #define int long long const int mod 1e9 7; int a[(int)2e6]; signed main() {int t, k;cin >> t >> k;a[0] 1;for (int i 1; i < 1e5 5; i){a[i] a[i - 1];a[i] % mod;i…

逆向映射是干嘛的anon_vma, vma, anon_vma_chain

逆向映射是为了从page得到进程信息&#xff0c;里面有三个比较重要的结构体&#xff1a; mm_area_struct, anon_vma_chain, anon_vma 想象一种复杂的场景 所以其实一个进程对应着很多anon_vma才对 进程A&#xff1a;mmap了16K的匿名页出来&#xff0c;这16k应该是有一个vma&…

1359C. Mixing Water

C. Mixing Water 一个简单的思维。 因为是一隔一的&#xff0c;所以要么热水多放一个&#xff0c;要么冷水和热水一样多。 设热水与要求的差为cou1&#xff0c;冷水与要求的差为cou2。 所以我们先考虑两种情况&#xff1a; 1&#xff0c;cou1大于cou2&#xff0c;那么肯定是要…

读取txt文件赋值到DataGridView中

先查看txt是每条信息之间是通过什么分割&#xff0c;我是通过换行符&#xff08;\n&#xff09;分割的, 然后再看每一条信息中字段是通过什么分割&#xff0c;我的字段是通过 tab键&#xff08;\t&#xff09;分割。 第一步 先获取到txt文件的路径&#xff1a; //获取绝对路径v…

Combobox报错:row[opts.textField].toLowerCase is not a function。

使用easyui框架加载combobox。 html页面&#xff1a; <span class"search_item"><span class"item_text">账号ID:</span><span class"item_obj"><input class"easyui-textbox" type"text" name&…

c++ 线程什么时候run_多线程并发支撑基础之JAVA内存模型

Java内存模型可以说是Java并发的底层支持&#xff0c;了解Java内存模型才能正在了解Java并发。内存模型在内存中设置一个变量"value 1&#xff1b;"那么其他线程能在什么时候读取到这个结果呢&#xff1f;有可能不能立即甚至永远都读不到。比如指令顺序与源代码中的…

1476D. Journey

D. Journey 一道简单线性dp#include <bits/stdc.h> using namespace std; const int N 5e5 3; char str[N]; int a[N],b[N]; int main() {int t;cin>>t;while (t--){int n;cin>>n;cin>>str1;for (int i0;i<n;i) a[i] b[i] 1;if (str[1]L) a[1]…

润乾报表 数据集ds1中,数据源xmglxt_x3无数据库连接,且未设定数据连接工厂,请检查数据源设定:...

一、润乾报表错误内容 产生数据工厂: com.runqian.report4.dataset.SQLDataSetFactory 失败 错误来源&#xff1a;: 数据集ds1中&#xff0c;数据源xmglxt_x3无数据库连接&#xff0c;且未设定数据连接工厂&#xff0c;请检查数据源设定&#xff1a; 二、解决方法 同事做的润乾…

1388C. Uncle Bogdan and Country Happiness

C. Uncle Bogdan and Country Happiness 纯纯DFS#include <bits/stdc.h> using namespace std; const int N 1e5 3; #define int long long int a[N], b[N], c[N]; vector<int> cun[N]; int vis[N]; int ff 1; void DFS(int x) {int res 0;int xx a[x];for (…

WPF中的数据绑定Data Binding使用小结

完整的数据绑定的语法说明可以在这里查看&#xff1a; http://www.nbdtech.com/Free/WpfBinding.pdf MSDN资料&#xff1a; Data Binding: Part 1 http://msdn.microsoft.com/en-us/library/aa480224.aspx Data Binding: Part 2 http://msdn.microsoft.com/en-us/library/aa480…

awr报告分析 mysql_AWR报告的生成和简单分析方法

生成AWR报告方法&#xff1a; 第一步&#xff1a;数据库压力测试卡开始时&#xff1a;生成第一个快照&#xff1a; Sqlexec dbms_workload_repository.create_snapshot(); 第二步&#xff1a;数据库压力测试结束时&#xff1a;生成第二个快照 Sqlexec dbms_workload_repository…

1560F1. Nearest Beautiful Number (easy version)

F1. Nearest Beautiful Number (easy version) 预处理加二分#include <bits/stdc.h> using namespace std; const int N 3e5 3; #define int long long set<int>cun1,cun2; signed main() {//单个for (int i1;i<9;i){int res 0;for (int j0;j<9;j) {res …

sqlserver 微信昵称_sql server用户名和登录名的区别和联系

在SQLSERVER数据库中&#xff0c;guest帐户是特殊的用户帐户。如果用户使用USE database语句访问的数据库中没有与此用户关联的帐户&#xff0c;此用户就与guest用户相关联。另外SQLSERVER采取登录名-用户名的安全规则&#xff0c;和Oracle里面的schema有点像。SQLSERVER使用所…

1506G. Maximize the Remaining String

G. Maximize the Remaining String 贪心&#xff0c;放置时&#xff0c;如果前面一个小比他小&#xff0c;并且后面还有&#xff0c;那么就把前面的删除#include <bits/stdc.h> using namespace std; const int N 3e5 3; #define int long long string str; char ans[…

bzoj 1208

1208: [HNOI2004]宠物收养所 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 9775 Solved: 3918[Submit][Status][Discuss]Description 最近&#xff0c;阿Q开了一间宠物收养所。收养所提供两种服务&#xff1a;收养被主人遗弃的宠物和让新的主人领养这些宠物。每个领养者都…

.net千万级数据导出_记一次解决docker下oracle数据库故障事例

一、问题背景&#xff1a;某个项目的线上环境oracle数据库挂了&#xff0c;同事急匆匆来找我救火。我简单咨询了一些基本情况&#xff1a;线上环境&#xff0c;docker部署&#xff0c;已正常运行半年。由于宿主机的根目录硬盘空间不够&#xff0c;运维的同事想把oracle数据文件…