将 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.ARRAY
或oracle.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 过程时设置时区的主要内容,如果未能解决你的问题,请参考以下文章
PL/SQL:, 如何将变量传递给 SELECT 语句并返回所有结果行