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

时间:2014-08-05 08:58:45

标签: java oracle jdbc plsql

我正在从Java调用plsql package procedure。此过程的类型参数带有timestamp。当我将timestamp参数直接设置为过程时,我可以指定Calendar object来声明使用e的时区。克。

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过程的一个参数。

1 个答案:

答案 0 :(得分:0)

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

  1. 实现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
    }
    
  2. 现在你创建一个这些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);
    
  3. 最后你像往常一样叫你plsql程序:

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