select语句中的JDBC数字溢出

时间:2015-03-06 00:00:51

标签: java jdbc

我有一个java应用程序,它执行用户在UI上输入的SQL select语句。应用程序获取元数据以了解列类型:

ResultSetMetaData metadata = rs.getMetaData();
int numColumns = metadata.getColumnCount();
for (int i=1;i<=numColumns;i++){
    column[i] = metadata.getColumnType(i);  
}

获得结果集后,对于每一行,我遍历列以了解类型。根据类型,我使用getInt(),getDate()或getString()获取值。

问题是在某些情况下,select有一个大的SUM(),当我执行getInt()时会出现数字溢出(我从JDBC驱动程序得到错误,在我的情况下是Sybase)。问题是getInt()中获得的数量大于int的容量。

一种解决方案是使用getLong()而不是getInt(),但是由于我事先并不知道用户输入的选择列,我可能会使用getLong()非常小数值,大量的数据将完全浪费64位字段。

任何想法如何解决这个问题?

3 个答案:

答案 0 :(得分:0)

在64位CPU的时代,可能getLong()毕竟不会是浪费。但即使getLong()可能会溢出,所以你更安全但不安全。 BigDecimal让您安全无虞。由于您将应用程序描述为 UI ,其中用户输入语句,因此瓶颈很可能是用户本身或JDBC,而不是Java。

您可以使用ResultSetMetaData.getColumnType(int column)来确定列的类型,并根据该类型选择Java类型。您可以使用ResultSetMetaData.getColumnClassName(int column)找出驱动程序建议的Java类,并使用ResultSet.getObject(int column)来检索数据。这是否真的很方便也可能取决于驾驶员的质量。

答案 1 :(得分:0)

当用户想要数字列上的long时,我建议您始终使用下一个较大的数据类型(在本例中为intSUM)。

原因是因为你要花费至少那么多的内存和处理来试图找出无论如何要使用哪种数据类型。您也可以保持代码简单并升级到下一个更大的类型。

答案 2 :(得分:0)

你可以做到&#34;乐观&#34;为您的列缓冲:从您的列数据的int(或甚至short)缓冲区开始,并将您的获取循环包装在try / catch中以应对该溢出异常。如果你抓住了一个,那么通过尝试越来越多地检索缓冲区数据类型,检查你需要多宽的范围&#34; wide&#34; (short - &gt; int - &gt; long - &gt; BigInteger / BigDecimal)类型。然后调整该列的缓冲区大小(通过分配更宽类型的新缓冲区并复制先前行的值)并重新开始检索。

但这是非常复杂的代码。如果你能负担得起内存,那么最好只使用longBigInteger / BigDecimal。您应该检查某些示例数据集的实际大小和节省的内存。 (并且当你最终不得不加宽时,请注意缓冲区重新分配的成本。)如果实际上结果集大小很容易适合用户使用更简单的long或更简单的用户更广泛的检索,然后没有问题,你不必解决它。