将 oracle.sql.ARRAY 传递给 PL/SQL 过程时设置时区

Posted

技术标签:

【中文标题】将 oracle.sql.ARRAY 传递给 PL/SQL 过程时设置时区【英文标题】:Setting time zone when passing oracle.sql.ARRAY to PL/SQL procedure 【发布时间】:2014-08-05 08:58:44 【问题描述】:

我正在从 Java 中调用 plsql package procedure。这个过程有一个带有timestamp 的类型参数。当我将时间戳参数直接设置为过程时,我可以指定 Calendar object 来声明要使用的时区 e。 g.

Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
statement.setTimestamp(1, new Timestamp(calendar.getTimeInMillis()), calendar);

有没有办法在使用oracle.sql.ARRAYoracle.sql.STRUCT 时声明时区?

使用的类型声明如下:

CREATE OR REPLACE TYPE "TY_EVENT_OBJECT"
AS
OBJECT
(
timestamp_event              date,
state                        number(15),
parameter_name               varchar2(248),
value                        number(15)
);

CREATE OR REPLACE TYPE "TY_EVENTS"
AS
TABLE OF TY_EVENT_OBJECT;

TY_EVENTS 类型是我必须使用的 plsql 过程的一个参数。

【问题讨论】:

你的数组是什么 DB 数据类型,DATE/TIMESTAMP 的表或变量数组?为什么不能以相同的方式填充匹配 Java 集合的每个元素? @AlexPoole 它不是时间戳的集合,它是一种对象类型。你的第二个问题我没看懂,我们使用的plsql api需要调用这个plsql api。 那么您是传递这些对象的数组还是单个对象?显示过程规范和调用它的 Java 代码可能会让事情变得更清楚(无论如何对我来说!) 【参考方案1】:

当您使用用户定义的 oracle 类型时,无法简单地传递将用于时区转换的日历。当使用 oracle.sql.ARRAY 和 oracle.sql.STRUCT 时,ojdbc 使用本地日历将 java.sql.Date 转换为 oracle.sql.DATE 因此存储在数据库中的实际日期,在您的情况下,是没有时区的本地时间. 因此,如果您希望日期以 UTC 格式存储到数据库中,则必须使用 UTC 日历手动将 java.sql.Date 转换为 oracle.sql.DATE。 你可以这样做:

    实现 SQLData 接口并覆盖方法。 注意: -getSQLTypeName 必须返回数据库中定义的实际类型名称,否则不起作用。 - 我们在下面使用 java.sql.Date,这很重要。因此,如果您希望在 TyEventObject 之外使用 java.util.Date,您可以创建一个执行转换的 setter/getter

    public class TyEventObject implements SQLData 
    
      private String sqlTypeName = "TY_EVENT_OBJECT";
      private java.sql.Date timestampEvent;
      private long state;
      private String parameterName;
      private long value;
    
      @Override
      public String getSQLTypeName() throws SQLException 
        return sqlTypeName;
      
    
      @Override
      public void readSQL(SQLInput stream, String typeName) throws SQLException 
        sqlTypeName = typeName;
    
        // Reading date in UTC time 
        OracleJdbc2SQLInput oracleStream = (OracleJdbc2SQLInput) stream;
        DATE oracleDate = (DATE)oracleStream.readOracleObject();
        if( oracleDate != null) 
          timestampEvent = oracleDate.dateValue( Calendar.getInstance(TimeZone.getTimeZone("UTC")));
         else 
          timestampEvent = null;
        
    
        state = stream.readLong();
        parameterName = stream.readString();
        value = stream.readLong();
      
    
      @Override
      public void writeSQL(SQLOutput stream) throws SQLException 
        // Writing timestamp in UTC time 
        OracleSQLOutput oracleStream = (OracleSQLOutput) stream;
        if( timestampEvent != null) 
          DATE oracleDate = new DATE( timestampEvent, Calendar.getInstance(TimeZone.getTimeZone("UTC")));
          oracleStream.writeOracleObject( oracleDate);
         else 
          stream.writeDate( null);
        
        stream.writeLong( state);
        stream.writeString( parameterName);
        stream.writeLong( value);
      
    
    // add public getters and setters
    
    

    现在您创建一个由这些 TyEventObject 对象组成的数组,以像这样传递给 plsql 过程(注意 Array 是 java.sql.Array):

    // I assume that your event objects that you want to save are in the list eventObjects
    TyEventObject[] entries = new TyEventObject[ eventObjects.size()];
    for( int i=0; i < eventObjects.size(); i++) 
      entries[i] = new TyEventObject();
      // You set the properties here
      // entries[i].setTimestampEvent( eventObjects.get( i).getTimestampEvent());
    
    
    Array dataObjectArray = connection.createArrayOf( "TY_EVENTS", entries);
    

    最后你像往常一样称你为plsql过程:

    CallableStatement cs = connection.prepareCall("call ProcedureName( ?)");
    cs.setObject(1, dataObjectArray, Types.ARRAY);
    cs.execute(); 
    cs.close();
    

【讨论】:

以上是关于将 oracle.sql.ARRAY 传递给 PL/SQL 过程时设置时区的主要内容,如果未能解决你的问题,请参考以下文章

oracle pl/sql 将异常类型传递给函数

将数组传递给 PostgreSQL PL/pgSQL 函数

PL/SQL:, 如何将变量传递给 SELECT 语句并返回所有结果行

每个将表名传递给过程的 ORACLE PL/SQL

将数据集合从 .NET 传递给 PL/SQL 包过程或函数?

将常规 CURSOR 传递给需要 SYS_REFCURSOR 的 PL/SQL 过程