gpt4 book ai didi

java - oracle.sql.ArrayDescriptor 中的错误?

转载 作者:行者123 更新时间:2023-12-02 04:20:18 28 4
gpt4 key购买 nike

今天,当数据库更新但 Web 应用程序未重新启动时,我们的 Web 应用程序出现了问题。
经过调查,我们发现在数据库更新期间,一个用户定义的类型被删除并再次创建。
类型没有改变 - 它只是被删除并使用与之前相同的 sql 语句再次创建。

下面的代码可以显示这个问题。
执行第二条预准备语句时出现 java.sql.SQLSyntaxErrorException“ORA-00902:无效数据类型”。

String str = "select * from MYTESTTABLE where test in (select column_value from TABLE (?) tmp)";

OracleConnection conn = null;
Properties connectionProps = new Properties();
connectionProps.put("user", "user");
connectionProps.put("password", "pwd");

conn = (OracleConnection) DriverManager
.getConnection("conn", connectionProps);

Statement stmt = conn.createStatement();
stmt.execute("drop table mytesttable");
stmt.execute("create table MYTESTTABLE ( test NUMBER(22))");
System.out.println("Table MYTESTTABLE was created");

stmt.execute("drop type my_type");
System.out.println("Type my_type was dropped");
stmt.execute("create type my_type as table of NUMBER(22)");
System.out.println("Type my_type was created");

String[] northEastRegion = { "10022", "02110", "07399" };

oracle.sql.ARRAY arr1 = new oracle.sql.ARRAY(
oracle.sql.ArrayDescriptor.createDescriptor("MY_TYPE", conn),
conn, northEastRegion);

PreparedStatement ps = conn.prepareStatement(str);
ps.setArray(1, arr1);
ps.executeQuery();

stmt.execute("drop type my_type");
System.out.println("Type my_type was dropped");
stmt.execute("create type my_type as table of NUMBER(22)");
System.out.println("Type my_type was created");

oracle.sql.ARRAY arr2 = new oracle.sql.ARRAY(
oracle.sql.ArrayDescriptor.createDescriptor("MY_TYPE", conn),
conn, northEastRegion);

ps = conn.prepareStatement(str);
ps.setArray(1, arr2);
ps.executeQuery(); //java.sql.SQLSyntaxErrorException: ORA-00902: invalid datatype

为什么 arr1 和 arr2 被视为不同的类型?
据我了解,问题在于这些类型具有不同的 OID。
但在 java 代码中,我仅通过名称来处理这些类型。我不使用 OID。

如何处理这个问题?
更新数据库后我们是否应该始终重新启动Web应用程序?即使数据库的结构没有改变。
或者我们应该在创建 MY_TYPE 时指定(硬编码)OID?
正确的做法是什么?

更新:
在我看来,我已经在 oracle.sql.ArrayDescriptor 中找到了答案和错误。
请参阅下面我的回答。

最佳答案

oracle.sql.ArrayDescriptor使用缓存。
默认情况下,将从缓存中加载同一 ArrayDescriptor 的第二个实例。
它与数据库中的类型不同,因为数据库中的类型是重新创建的。

ArrayDescriptor中有一个构造函数,您可以在其中指定是否替换任何缓存的描述符。

static ArrayDescriptor  createDescriptor(java.lang.String name, java.sql.Connection conn, boolean recurse, boolean force)
static ArrayDescriptor createDescriptor(SQLName sqlName, java.sql.Connection conn, boolean recurse, boolean force)

但是构造函数中存在一个错误,其中第一个参数是 String - 该构造函数的主体中未使用强制参数。
它仅在具有 SQLName 的构造函数主体中使用。
您可以查看例如 here 的代码。

因此,为了解决我们的问题,我们可以使用 SQLName 并将参数强制设置为 true 的构造函数。在这种情况下,不会使用缓存。

String[] northEastRegion = { "10022", "02110", "07399" };
String str = "select * from MYTESTTABLE where test in (select column_value from TABLE (?) tmp)";

OracleConnection conn = null;
Properties connectionProps = new Properties();
connectionProps.put("user", "user");
connectionProps.put("password", "pwd");

conn = (OracleConnection) DriverManager
.getConnection("connstr", connectionProps);

Statement stmt = conn.createStatement();

stmt.execute("drop table mytesttable");
stmt.execute("create table MYTESTTABLE ( test NUMBER(22))");

stmt.execute("drop type my_type1");
stmt.execute("create type my_type1 as table of NUMBER(22)");

ArrayDescriptor desc1 = oracle.sql.ArrayDescriptor.createDescriptor("MY_TYPE1", conn);

stmt.execute("drop type my_type1");
stmt.execute("create type my_type1 as table of NUMBER(22)");

oracle.sql.SQLName sqlName = new oracle.sql.SQLName("MY_TYPE", conn);
ArrayDescriptor desc2 = oracle.sql.ArrayDescriptor.createDescriptor(sqlName, conn, true, true);
oracle.sql.ARRAY arr2 = new oracle.sql.ARRAY(desc2, conn, northEastRegion);

PreparedStatement ps = conn.prepareStatement(str);
ps.setArray(1, arr2);
ps.executeQuery();

关于java - oracle.sql.ArrayDescriptor 中的错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32849342/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com