HIbernate Oracle存储过程
之前为了实现基于Hibernate+Oracle的存储过程调用,发现了一个又一个坑,然后一个一个的尝试解决。
需求:使用Hibernate调用Oracle的存储过程,需要支持的有动态表名、存储过程变量定义、数组传递
1. oracle变量定义
首先,需要解决的是如何在oracle存储过程中定义变量,否则连存储过程都没法写
变量赋值
- 在AS…BEGIN中间插入要定义的变量
foo - 使用
select into foo语法
-- http://stackoverflow.com/questions/16260068/assign-a-select-to-a-variable-in-a-stored-procedurecreate or replaceFUNCTION PCD_COMBAT (identifier_perso NUMBER, identifier_advers NUMBER)RETURN NUMBERASATT_PERSO NUMBER;OFF_PERSO NUMBER;DEF_ADVERS NUMBER;BEGINSELECT OFFENSE_PERSOINTO OFF_PERSOFROM PERSONNAGEWHERE ID_PERSO = identifier_perso;SELECT DEFENSE_ADVERSAIREINTO DEF_ADVERSFROM PERSONNAGEWHERE ID_ADVERSAIRE = identifier_advers;ATT_PERSO := OFF_PERSO - DEF_ADVERS;IF ATT_PERSO <1 THENATT_PERSO :=1;END IFRETURN ATT_PERSO;END PCD_COMBAT;
复杂变量+package(未使用到)
Another reason that standalone procedures and functions, like the ones in “Creating and Using Standalone Procedures and Functions” , are limited to large-scale development is that they can only send and receive scalar parameters ( NUMBER , VARCHAR2, and DATE ), but cannot use a composite structure, RECORD , unless it is defined in a package specification.
https://docs.oracle.com/cd/B28359_01/appdev.111/b28843/tdddg_procedures.htm#CIHCHIDB
2. Hibernate存储过程调用
一个简单的存储过程写完了,得先测试能否使用hibernate对存储过程进行调用,所以接下来了解Hibernate是如何调用存储过程的。稍微查一下,发现调用还是相当简单的。但是,是有一些限制和条件的。
使用hibernate.query限制
For Oracle the following rules apply:
- A function must return a result set. The first parameter of a procedure must be an
OUTthat returns a result set. This is done by using aSYS_REFCURSORtype in Oracle 9 or 10. In Oracle you need to define aREF CURSORtype. See Oracle literature for further information.https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch18.html#sp_query
不使用query
如果不能满足Hibernate对query对象的使用条件,就只能自己使用session进行相对原生一些的调用。虽然官方文档给出了session.connection(),但是,明显这个文档也是一段时间没有更新了。在4.X版本中,这个接口已经没有了。因此,进一步找了一些替代方案
seesion.connection()
http://stackoverflow.com/questions/15217984/alternative-of-deprecated-hibernate-getsession-connection
connection异常
用了connection()跟着又有异常发生,看上去是安全策略和对象包装造成的,解决方案如下:
http://www.coderanch.com/t/415597/JDBC/databases/Apache-Commons-DBCP-connection-object
https://community.oracle.com/thread/2564233?start=0&tstart=0
accessToUnderlyingConnectionAllowed="true"
conn = ((DelegatingConnection) conn).getInnermostDelegate();
3. 变量类型
一个简单的存储过程的调用搞定了,就是后面的重头戏,表名做参数、传递数组参数。。。这是个大坑!大坑!!大坑!!!
表名做参数
表名做参数,有点像是Javascript的eval(),让一个字符串可执行
除了下面的例子显示的,还有使用DBMS.parse()
-- https://community.oracle.com/thread/1122692?tstart=0CREATE OR REPLACE PROCEDURE "P_1"( TAB1 VARCHAR2)ASfield1 CHAR(5);field2 CHAR(5);c1 sys_refcursor;beginl_str :='select a,b,c from '||tab1||' INNER JOIN tab2 ON a = .......';open c1 from l_str;/*OPEN C1;CURSOR C1ISSELECT a, b , cFROM TAB1INNER JOINtab2ON a = .......OPEN C1;*/LOOPFETCH C1INTO .....EXIT WHEN C1%NOTFOUND;.....END;END LOOP;CLOSE C1;EXCEPTIONWHEN OTHERS.....END;
数组做参数
这绝对是大坑,神坑!
http://stackoverflow.com/questions/23573303/send-retrieve-array-list-to-oracle-stored-procedure
http://www.codeproject.com/Articles/164705/Oracle-PL-SQL-collections
http://viralpatel.net/blogs/java-passing-array-to-oracle-stored-procedure/
-- http://xiaogui9317170.iteye.com/blog/286401create table study_array_nick_tab(name varchar2(200));create or replace type study_array_nick_list is VARRAY(1000) of varchar2(200);create or replace procedure study_array_nick(in_array in study_array_nick_list)isv_i number;beginfor v_i in1.. in_array.count loopinsert into study_array_nick_tab(name) values(in_array(v_i));end loop;commit;exception when others thenrollback;raise_application_error('20999','测试错误');end study_array_nick;
-- http://forum.spring.io/forum/spring-projects/data/24224-how-can-i-pass-arraylist-to-stored-procedure/page2CREATE OR REPLACE TYPE TEST_EMP_OBJ AS OBJECT (empno number, empname varchar2(30));create or replace type TEST_EMP_OBJ_ARRAY as table of TEST_EMP_OBJ;create table test_emp (empno number, empname varchar2(30));CREATE OR REPLACE PROCEDURE TEST_EMP_OBJ_ARRAY_PROC ( p_obj_array in TEST_EMP_OBJ_ARRAY ) ASbeginfor i in1..p_obj_array.count loopinsert into test_emp (empno, empname)values(p_obj_array(i).empno, p_obj_array(i).empname);end loop;end;
ORACLE+JAVA
照着上面的那些例子,写了存储过程,然后通过Hibernate调用,实际上一个都没有成功。不传递数组就没问题,传递数组就会报异常,大意是参数无法转化为Oracle的表示。然后找到下面这个完整的例子,照着一模一样敲了一遍,除了那个IDS的TYPE我定义,而是直接用了varchar(32),结果就是不行。。。
https://oracle-base.com/articles/misc/using-ref-cursors-to-return-recordsets#11g-updates
SQL> CREATE OR REPLACE TYPE IDS AS OBJECT ( id1 NUMBER, id2 NUMBER, id3 NUMBER );2/Type createdSQL> CREATE OR REPLACE TYPE IDS_TABLE AS TABLE OF IDS;--这里我用的是OF varvchar(32)2/Type createdSQL> CREATE OR REPLACE PROCEDURE getInfo(p_ids IN IDS_TABLE) IS2BEGIN3 FOR i IN 1.. p_ids.COUNT LOOP4 dbms_output.put_line(p_ids(i).id15||','|| p_ids(i).id26||','|| p_ids(i).id3);7END LOOP;8END getInfo;9/Procedure created
SQL> CREATE OR REPLACE2 AND COMPILE JAVA SOURCE NAMED "ArrayDemo"3as4import java.io.*;5import java.sql.*;6import oracle.sql.*;7import oracle.jdbc.driver.*;89publicclassArrayDemo{1011publicstaticvoid passArray()throwsSQLException{1213Connection conn =14newOracleDriver().defaultConnection();151617//这里没有定义IDS18StructDescriptor itemDescriptor =StructDescriptor.createDescriptor("IDS",conn);1920Object[] itemAtributes =newObject[]{newInteger(1),21newInteger(2),22newInteger(3)};23 STRUCT itemObject1 =new STRUCT(itemDescriptor,conn,itemAtributes);2425 itemAtributes =newObject[]{newInteger(4),26newInteger(5),27newInteger(6)};28 STRUCT itemObject2 =new STRUCT(itemDescriptor,conn,itemAtributes);2930 STRUCT[] idsArray ={itemObject1,itemObject2};3132ArrayDescriptor descriptor =33ArrayDescriptor.createDescriptor("IDS_TABLE", conn );34//在这里直接穿了String的List。明明构造函数是有这种构造的35 ARRAY array_to_pass =36new ARRAY( descriptor, conn, idsArray );37//然后调用就是出现异常38OraclePreparedStatement ps =39(OraclePreparedStatement)conn.prepareStatement40("begin getInfo(:x); end;");4142 ps.setARRAY(1, array_to_pass );43 ps.execute();4445}46}47/Java created
SQL> CREATE OR REPLACE2 PROCEDURE show_java_calling_plsql3 AS LANGUAGE JAVA4 NAME 'ArrayDemo.passArray()';5/Procedure createdSQL>exec show_java_calling_plsql ;1,2,34,5,6PL/SQL procedure successfully completed
4. 结论
关于使用Hibernate+Oracle存储过程,除了最后的数组参数没有搞定,其他的都尝试成功了。关于数组参数这个问题,我还是不知道怎么解决。难道一定要定义一个只包含一个字符串的OBJECT(就像上面的那个IDS一样)?这个没有进一步解决了。将这整个过程记录下来,权当整理。
HIbernate Oracle存储过程的更多相关文章
- Oracle存储过程学习使用
存储过程创建语法: create or replace procedure 存储过程名(param1 in type,param2 out type) as 变量1 类型(值范围); 变量2 类型(值 ...
- oracle 存储过程的基本语法
原文:oracle 存储过程的基本语法 1.基本结构 CREATE OR REPLACE PROCEDURE 存储过程名字( 参数1 IN NUMBER, 参数2 IN NUMBER) I ...
- oracle 存储过程 ,触发器练习
/*以下代码是对emp表进行显示宽度设置 */col empno for 9999;col ename for a10;col job for a10;col mgr for 9999;col hir ...
- Oracle 存储过程_(收集)
oracle 存储过程的基本语法 1.基本结构 CREATE OR REPLACE PROCEDURE 存储过程名字( 参数1 IN NUMBER, 参数2 IN NUMBER) IS变量 ...
- 关于oracle存储过程的若干问题备忘
1.在oracle中,数据表别名不能加as,如: select a.appname from appinfo a;-- 正确select a.appname from appinfo as a;-- ...
- ORACLE存储过程详解
1.定义 所谓存储过程(Stored Procedure),就是一组用于完成特定数据库功能的SQL语句集,该SQL语句集经过编译后存储在数据库系统中.在使用时候,用户通过指定已经定义的存储过程名字并给 ...
- oracle 存储过程
来自:http://www.jb51.net/article/31805.htm Oracle存储过程基本语法 存储过程 1 CREATE OR REPLACE PROCEDURE 存储过程名 2 I ...
- Oracle存储过程语法
原文链接:http://www.jb51.net/article/31805.htm Oracle存储过程基本语法 存储过程 1 CREATE OR REPLACE PROCEDURE 存储过程名 ...
- ORACLE存储过程调用Web Service
1. 概述 最近在ESB项目中,客户在各个系统之间的服务调用大多都是在oracle存储过程中进行的,本文就oracle存储过程调用web service来进行说明.其他主流数据库,比如mysql和sq ...
随机推荐
- 查看MySQL数据库的默认编码
查看MySQL数据库的默认编码 1.使用status命令能够显示数据库的相关系信息,示例如下: mysql> status;————–mysql Ver 14.12 Distrib 5.0.77 ...
- FTP服务器上删除文件夹失败
很多人都知道:要删除FTP服务器上的文件夹时,必须确保文件夹下面没有其他文件,否则会删除失败! 可是,有些服务器考虑到安全等因素,通常会隐藏以点开始的文件名,例如“.test.txt”.于是,有的坏人 ...
- Cocos2D-X v3.0 alpha1环境搭建
周末看了下Cocos2D,感觉用起来还是挺爽的样子,跨平台,支持Windows, Linux, Mac, IOS, Android,WP...N多平台..还是C++开源滴,果断下下来研究下.. 最新版 ...
- 二十六个月Android学习工作总结
1.客户端的功能逻辑不难,UI界面也不难,但写UI花的时间是写功能逻辑的两倍. 2.写代码前的思考过程非常重要,即使在简单的功能,也需要在本子上把该功能的运行过程写出来. 3.要有自己的知识库,可以是 ...
- c++ THUNK技术
这里想说的是:代码中的关键点为用指令jmp pFunc跳转到你想要运行的函数pFunc. 指令"jmp xxxx"占5个字节,代码中用了个一字节对齐的结构体struct Thunk ...
- 腾讯2013笔试题—web前端笔试题 (老题练手)
问题描述(web前端开发附加题1): 编写一个javascript的函数把url解析为与页面的javascript.location对象相似的实体对象,如:url :'http://www.qq.co ...
- 自定义控件(视图)2期笔记01:自定义控件之自定义View的步骤
1. 根据Android Developers官网的介绍,自定义控件你需要以下的步骤: (1)创建View (2)处理View的布局 (3)绘制View (4)与用户进行交互 (5)优化已定义的Vie ...
- CentOS LiveCD LiveDVD DVD 等版本的区别
1.CentOS系统镜像DVD有两个,安装系统只用到第一个镜像即CentOS-6.7-x86_64-bin-DVD1.iso,第二个镜像CentOS-6.7-x86_64-bin-DVD2.iso是系 ...
- ftp nfs samba比较
首先从字面意思上区分一下:1. FTP(文件传输协议)2. NFS(网络文件系统)3. samba 即smb(服务信息块)协议其中FTP 是TCP/IP协议栈所提供的一种子协议,该子协议具体可以实现在 ...
- c#中的面向对象基础知识总结
面向对象 1.面向过程----->面向对象 1. 面向过程:面向的是完成这件事儿的过程,强调的是完成这件事儿的动作. 面向对象:意在写出一个通用的代码,屏蔽差异. 我们在代码中描述一个对象,通 ...