关于JDBC访问存储过程的问题
最近开发一个应用,需要调用一个入参为List的存储过程。
存储过程为: proc_test(p1 OUT Number, p2 IN Number, p3 IN TAB_CUSTOMER);
这个List入参是一个在oracle中自定义的类型的表,如下:
CREATE OR REPLACE TYPE TAB_CUSTOMER AS TABLE OF TYP_CUSTOMER;
CREATE OR REPLACE TYPE TYP_CUSTOMER AS OBJECT
(
ID VARCHAR2(20),
NAME VARCHAR2(20),
GENDER NUMBER,
AGE NUMBER,
BIRTHDAY DATE
);
问题一:如何传List对象给oracle存储过程
一 开始我使用jpa的@Procedure,结果一直报错:参数个数或参数类型错误。我在项目中
定义了一个实体类Customer,和Oracle中的类型TYP_CUSTOMER字段相同。传了一个
List<Customer>给存储过程。java.util.List无法转换成存储过程需要的oracle.sql.ARRAY对象。
后来咨询了又相关经验的同事,问题解决,代码如下:
【以下代码解决如何传oracle.sql.ARRAY给存储过程的问题】
import java.util.List;
import java.sql.Connection;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
import oracle.sql.DATE;
/*
以下方法返回一个oracle.sql.ARRAY对象,该对象与oracle中自定
的对象的表映射。
@param oracleType oracle中自定义的类
@param oracleTable oracle中自定义的类的表
@list 本地封装的数据列表
@return ARRAY 一个oracle.sql.ARRAY对象,该对象可与oracle中自定
的对象的表映射。
*/
private ARRAY getOracleArray(Connection con, String oracleType, String oracleTable, List<Customer> list)
throws Exception {
ARRAY array = null;
ArrayDescriptor desc = ArrayDescriptor.createDescriptor(oracleTable, con);
STRUCT[] structs = new STRUCT[list.size()];
if (list != null && list.size() > 0) {
StructDescriptor structdesc = new StructDescriptor(oracleType, con);
for (int i = 0, len = list.size(); i < len; i++) {
Object[] result = {
list.get(i).getId(),
list.get(i).getName(),
list.get(i).getGender(),
list.get(i).getAge(),
new DATE(new java.sql.Date(list.get(i).getBirthday().getTime()))};
structs[i] = new STRUCT(structdesc, con, result);
}
array = new ARRAY(desc, con, structs);
} else {
array = new ARRAY(desc, con, structs);
}
return array;
}
import java.util.Date;
class Customer {
int id;
String name;
String gender;
int age;
Date birthday;
/* 省略getter/setter */
}
问题二:只能发起连接池的最大连接数量的请求
问题代码如下:
@Autowired
private HikariDataSource hikariDataSource;
public void save(List<Customer> customers, int p2) {
Connection conn = null;
try {
conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("call PKG_TEST.PROC_TEST(?,?,?)");
ARRAY p3 = getOracleArray(conn, TYP_CUSTOMER, TAB_CUSTOMER, customers);
int p1 = 0;
pstmt.setInt(1, p1);
pstmt.setInt(2, p2);
pstmt.setArray(3, p3);
pstmt.execute();
pstmt.close();
} catch (SQLException e) {
throw new PersistException(e);
} catch (Exception e) {
throw new PersistException(e);
} finally {
if(conn != null)
try{
conn.close();
}catch(Exception e){
throw new PersistException(e);
}
}
}
private Connection getConnection() {
Connection conn = null;
try {
conn = hikariDataSource.getConnection();
DatabaseMetaData metaData = conn.getMetaData();
conn = metaData.getConnection();
} catch (SQLException e) {
throw new PersistException(e);
}
return conn;
}
class PersistException extends RuntimeException{ /*省略*/}
我这里注入了HikariDataSource,因为Hikari的Connection无法直接cast为
Oracle的Connection,所以做了以上转换。
看起来,一次访问数据库结束后,数据库连接没有释放。
【表查询也有同样的问题】
解决问题的代码如下:
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.hibernate.engine.spi.SessionImplementor;
@PersistenceContext
private EntityManager entityManager;
public void save(SaleRetrainingReport report) {
try {
Connection conn = entityManager.unwrap(SessionImplementor.class).connection();
CallableStatement stmt = conn.prepareCall("call PKG_TEST.PROC_TEST(?,?,?)");
ARRAY p3 = getOracleArray(toOracleConnection(conn), TYP_CUSTOMER, TAB_CUSTOMER, customers);
int p1 = 0;
stmt.setInt(1, p1);
stmt.setInt(2, p2);
stmt.setArray(3, p3);
stmt.execute();
stmt.close(http://www.my516.com);
} catch (SQLException e) {
throw new PersistException(e);
} catch (Exception e) {
throw new PersistException(e);
}
}
private Connection toOracleConnection(Connection connection) {
Connection conn = null;
try {
DatabaseMetaData metaData = connection.getMetaData();
conn = metaData.getConnection();
} catch (SQLException e) {
throw new PersistException(e);
}
return conn;
}
---------------------
关于JDBC访问存储过程的问题的更多相关文章
- Java数据库连接——JDBC调用存储过程,事务管理和高级应用
一.JDBC常用的API深入详解及存储过程的调用 相关链接:Jdbc调用存储过程 1.存储过程(Stored Procedure)的介绍 我们常用的操作数据库语言SQL语句在执行的时候需要先编译,然后 ...
- Java数据库连接--JDBC调用存储过程,事务管理和高级应用
相关链接:Jdbc调用存储过程 一.JDBC常用的API深入详解及存储过程的调用 1.存储过程的介绍 我们常用的操作数据库语言SQL语句在执行的时候要先进行编译,然后执行,而存储过程是在大型数据库系统 ...
- Jdbc访问数据库篇
一万年太久,只争朝夕 What JDBC 上部 JDBC(Java DataBase Connectivity)Java 数据库连接,主要提供编写 Java 数据库应用程序的 API 支持 java. ...
- JDBC访问数据库的具体步骤(MySql + Oracle + SQLServer)
* 感谢DT课堂颜群老师的视频讲解(讲的十分仔细,文末有视频链接) import java.sql.Connection; import java.sql.DriverManager; import ...
- Java jdbc访问sqlserver,oracle数据库
1.JDBC访问Oracle数据库 public class Jdbc_Oracle { // 静态代码块,只会执行一次,类似C#静态构造方法 static { try { // 加载数据库驱动一次 ...
- 如何通过JDBC访问数据库
Java数据库连接(JDBC)用与在Java程序中实现数据库操作功能,它提供了执行SQL语句.访问各种数据库的方法,并为各种不同的数据库提供统一的操作接口,java.sql包中包含了JDBC操作数据库 ...
- 使用JDBC访问SQLServer 2008
使用JDBC访问SQLServer 2008 // 准备数据库驱动程序 String driver = "com.microsoft.sqlserver.jdbc.SQLServerDriv ...
- jdbc调用存储过程的方法
----------------------------jdbc调用存储过程的方法---------------------------------------------------private ...
- java web中Jdbc访问数据库步骤通俗解释(吃饭),与MVC的通俗解释(做饭)
一.Jdbc访问数据库步骤通俗解释(吃饭) 1)加载驱动 Class.forName(“com.microsoft.jdbc.sqlserver.SQLServer”); 2) 与数据库建立连接 Co ...
随机推荐
- iOS之strong和copy
深拷贝和浅拷贝 深拷贝和浅拷贝主要是对类类型而言的,浅拷贝就是指针拷贝,深拷贝是对象拷贝. property的strong和copy 在接触iOS程序时经常会看到程序某些类类型属性被strong修饰, ...
- 状态空间搜索好题UVA10603
题目 分析:注意这里求的是最少流量, 二不是最少步数!!!所以我们用优先队列去维护一个最小流量,然后进行bfs即可,解释一下一个重要的数组ans[i],表示的是杯子中的水为i时的最小流量 #inclu ...
- leetcode 字符串动态规划总结
问题1:leetcode 正则表达式匹配 请实现一个函数用来匹配包括'.'和'*'的正则表达式.模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次). 在本题中,匹配 ...
- 插入符的创建(MFC)
int CDrawRectangleDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { ) ; // TODO: 在此添加您专用的创建代码 CreateSol ...
- 3.11-3.15 HDFS HA
一.背景 1. Hadoop2.0之前,在HDFS集群中NameNode存在单点故障(SPOF).对于只有一个NameNode的集群, 若NameNode机器出现故障,则整个集群将无法使用,直到Nam ...
- Codeforces - 1033C - Permutation Game - 简单dp - 简单数论
https://codeforces.com/problemset/problem/1033/C 一开始觉得自己的答案会TLE,但是吸取徐州赛区的经验去莽了一发. 其实因为下面这个公式是 $O(nlo ...
- hdoj1166【线段树】
单点更新+区间求和 不多说,直接上渣code--- #include<cstdio> #include<iostream> #include<string.h> # ...
- hdoj1027【STL系列。。。?】
这个太夸张了...感觉是有别的方法,但是觉得再说吧...以后碰到全排列应该也是用STL嗨的吧...嗯,,,就是这样的....?再说,再说.. 还有杭电支持c艹11,很棒 #include <bi ...
- 解决 Xshell 连接出现 The remote SSH server rejected X11 forwarding request 问题
问题描述 使用 Xshell 5 首次连接虚拟机 CentOS 7.6 出现这样的提示: WARNING! The remote SSH server rejected X11 forwarding ...
- 修改Cloudera Manager 管理机器的IP
原本在3台机器中部署了Cloudera CDH4.8的集群环境,运行状况良好,后来由于机房搬迁,导致那3台机器的ip地址被改变(hostname 没有变化). 再次启动Cloudera-scm-ser ...