关于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 ...
随机推荐
- 【总结——HTTP协议】
一.HTTP协议简介 什么是HTTP?全称是HyperText Transfer Protocal,即:超文本传输协议,从1990年开始就在WWW上广泛应用,是现今在WWW上应用最多的协议,目前版本是 ...
- git只clone仓库中指定子目录
基于sparse clone变通方法 [root@vm_test backup]# mkdir devops[root@vm_test backup]# cd devops/[root@vm_test ...
- 高效使用ppt素材
一.素材大致分为: 立体素材:以TG素材为代表的那种高光立体素材 平面素材:以咨询公司麦肯锡.罗兰贝格公司为代表的平面设计的素材 二.使用原则: 原则一:平面左边,立体右边 这个原则告诉你几件事: 如 ...
- Mysql基础调优
mysql基础的优化方式 1.利用索引加快查询速度 2.利用查询缓存或者旁挂式缓存,提高访问速度 缓存:k/v key:查询语句的hash值 value:查询语句的执行结果 哪些查询可能不会被缓存? ...
- E20170414-ms
collapse v/n 奔溃,垮台 constraint n 约束,限制 adaptive adj 适应的; 有适应能力的; exhausitive adj. 详尽的; store n 商店,仓 ...
- Codeforces - 346A - Alice and Bob - 简单数论
http://codeforces.com/problemset/problem/346/A 观察了一下,猜测和他们的最大公因数有关,除以最大公因数前后结果是不会变的. 那么怎么证明一定是有n轮呢?我 ...
- 洛谷 - P1198 - 最大数 - 线段树
https://www.luogu.org/problemnew/show/P1198 要问区间最大值,肯定是要用线段树的,不能用树状数组.(因为没有逆元?但是题目求的是最后一段,可以改成类似前缀和啊 ...
- c#删除指定文件夹中今天之前的文件
1.说明 使用Directory类对指定文件夹下的今天或者更早日期之前的文件进行删除.原文链接:http://www.cnblogs.com/lengzhan/p/6423943.html 2.代码 ...
- poj3417 闇の連鎖 【树上差分】By cellur925
闇の連鎖(yam.pas/c/cpp)题目描述传说中的暗之连锁被人们称为 Dark.Dark 是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它.经过研究,你发现 Dark 呈现无向图的结构,图中有 ...
- iOS NSUserDefaults [setValue:forKey:] [setObject:forKey:] <Objc> setValue(_,forKey:) set(_,forKey) <Swift 3>
前者其实是NSObject都可以调用的KVC方法,后者才是NSUserDefaults的实例方法: 这里参数的类型是nullable id,但是我建议你在传null的时候慎重考虑,否则你的应用就可能面 ...