最近开发一个应用,需要调用一个入参为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访问存储过程的问题的更多相关文章

  1. Java数据库连接——JDBC调用存储过程,事务管理和高级应用

    一.JDBC常用的API深入详解及存储过程的调用 相关链接:Jdbc调用存储过程 1.存储过程(Stored Procedure)的介绍 我们常用的操作数据库语言SQL语句在执行的时候需要先编译,然后 ...

  2. Java数据库连接--JDBC调用存储过程,事务管理和高级应用

    相关链接:Jdbc调用存储过程 一.JDBC常用的API深入详解及存储过程的调用 1.存储过程的介绍 我们常用的操作数据库语言SQL语句在执行的时候要先进行编译,然后执行,而存储过程是在大型数据库系统 ...

  3. Jdbc访问数据库篇

    一万年太久,只争朝夕 What JDBC 上部 JDBC(Java DataBase Connectivity)Java 数据库连接,主要提供编写 Java 数据库应用程序的 API 支持 java. ...

  4. JDBC访问数据库的具体步骤(MySql + Oracle + SQLServer)

    * 感谢DT课堂颜群老师的视频讲解(讲的十分仔细,文末有视频链接) import java.sql.Connection; import java.sql.DriverManager; import ...

  5. Java jdbc访问sqlserver,oracle数据库

    1.JDBC访问Oracle数据库 public class Jdbc_Oracle { // 静态代码块,只会执行一次,类似C#静态构造方法 static { try { // 加载数据库驱动一次 ...

  6. 如何通过JDBC访问数据库

    Java数据库连接(JDBC)用与在Java程序中实现数据库操作功能,它提供了执行SQL语句.访问各种数据库的方法,并为各种不同的数据库提供统一的操作接口,java.sql包中包含了JDBC操作数据库 ...

  7. 使用JDBC访问SQLServer 2008

    使用JDBC访问SQLServer 2008 // 准备数据库驱动程序 String driver = "com.microsoft.sqlserver.jdbc.SQLServerDriv ...

  8. jdbc调用存储过程的方法

    ----------------------------jdbc调用存储过程的方法---------------------------------------------------private ...

  9. java web中Jdbc访问数据库步骤通俗解释(吃饭),与MVC的通俗解释(做饭)

    一.Jdbc访问数据库步骤通俗解释(吃饭) 1)加载驱动 Class.forName(“com.microsoft.jdbc.sqlserver.SQLServer”); 2) 与数据库建立连接 Co ...

随机推荐

  1. SPOJ:Another Version of Inversion(二维数组的逆序对)

    DCE Coders admins are way much geekier than they actually seem! Kartik has been following that tradi ...

  2. 「NOIP2012」「LuoguP1083」 借教室

    Description 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的 ...

  3. javacv开发详解之1:调用本机摄像头视频(建议使用javaCV最新版本)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  4. 打印斐波那契(Fibonacci)数列

    需求:打印 Fibonacci数列 思路: 当前项的值等于前两项数值的和 F=(F-1)+F(F-2) 样例: 输入:10 输出:1 1 2 3 5 8 13 21 34 55 辗转相加法实现 #in ...

  5. 任务24:WebHost的配置

    24 任务24:WebHost的配置 创建HelloCore的项目 我们新建一个空的mvc项目 我们在这里调用COnfigureAppConfiguration方法更改默认的配置.为读取setting ...

  6. springcloud(一) 服务拆分

    一般我们的项目如果需要从单应用服务升级到微服务,必须要将原来的服务做拆分,我这边的拆分也是基于将之前spb-demo的springboot单应用做拆分,拆分出三个应用,spb-brian-query- ...

  7. Raphael.js改变元素层叠顺序

    Raphael.js 元素(Element)改变层叠顺序,Raphael.js是一个矢量绘图库兼容svg和vml.初学时感觉css的z-index能搞定,结果是不支持,不过矢量绘图符合dom标准.可以 ...

  8. 基于 React-draft-wysiwyg 实现的 react 富文本编辑器组件 开箱即用

    工作中遇到了一个需要做图文详情 的富文本编辑的需求, 于是基于 React-draft-wysiwyg 实现了一个 纯组件, 目前支持 常规文本输入 外部链接图片 以及本地上传图片, 由于是纯组件, ...

  9. 详解基于linux环境MySQL搭建与卸载

    本篇文章将从实际操作的层面,讲解基于linux环境的mysql的搭建和卸载. 1  搭建mysql 1.1  官网下载mysql压缩包 下载压缩包时,可以先把安装包下载到本地,再上传到服务器,也可以在 ...

  10. 分布式集群环境下,如何实现session共享四(部署项目测试)

    这是分布式集群环境下,如何实现session共享系列的第四篇.在上一篇:分布式集群环境下,如何实现session共享三(环境搭建)中,已经准备好了相关的环境:tomcat.nginx.redis.本篇 ...