Java CachedRowSetImpl getString基于列标签抛出;无效的列名";
当我执行以下代码时,一切正常:Java CachedRowSetImpl getString基于列标签抛出;无效的列名";,java,sql,jdbc,resultset,Java,Sql,Jdbc,Resultset,当我执行以下代码时,一切正常: ResultSet rs = con.prepareStatement("SELECT r.UID AS R FROM r").executeQuery(); System.out.println(rs.getMetaData().getColumnLabel(1)); rs.next(); System.out.println(rs.getString("R")); 结果是: R 23 但当我执行以下代码时: ResultSet rs = con.prepa
ResultSet rs = con.prepareStatement("SELECT r.UID AS R FROM r").executeQuery();
System.out.println(rs.getMetaData().getColumnLabel(1));
rs.next();
System.out.println(rs.getString("R"));
结果是:
R
23
但当我执行以下代码时:
ResultSet rs = con.prepareStatement("SELECT r.UID AS R FROM r").executeQuery();
CachedRowSetImpl rslt = new CachedRowSetImpl();
rslt.populate(rs);
System.out.println(rslt.getMetaData().getColumnLabel(1));
rslt.next();
System.out.println(rslt.getString("R"));
结果是:
R
java.sql.SQLException:列名无效
为什么它会在这里抛出异常?问题是
CachedRowSet
(com.sun.rowset.CachedRowSetImpl
)的参考实现包含一个错误:当您按名称检索列时,它使用columnName
,而不使用columnLabel
,因此,与JDBC规范的其余部分相反,JDBC规范使用columnLabel
来检索值。此错误使得无法通过columnLabel
从行集中检索值
甲骨文的错误是,但是(令人惊讶,令人惊讶)他们已经使它无法供公众观看
有两种可能的解决办法。一个是检查驱动程序是否提供了一个属性来同时让ResultSetMetaData.getColumnName(..)
方法返回columnLabel
值,第二个解决方法是创建CachedRowSetImpl
的子类(不幸的是,这需要大量重写方法)
以下版本是从此邮件复制的:
import java.math.BigDecimal;
导入java.sql.Array;
导入java.sql.Blob;
导入java.sql.Clob;
导入java.sql.Ref;
导入java.sql.SQLException;
导入java.util.Calendar;
导入java.util.Collection;
导入java.util.Hashtable;
导入javax.sql.rowset.RowSetMetaDataImpl;
导入com.sun.rowset.CachedRowSetImpl;
公共类FixedCachedRowSetImpl扩展了CachedRowSetImpl{
私有静态最终长serialVersionUID=-9067504047398250113L;
私有RowSetMetaDataImpl RowSetMD;
public FixedCachedRowSetImpl()引发SQLException{
超级();
}
public FixedCachedRowSetImpl(哈希表环境)引发SQLException{
高级工程师(环境);
}
private int getColIdxByName(字符串名)引发SQLException{
RowSetMD=(RowSetMetaDataImpl)this.getMetaData();
int cols=RowSetMD.getColumnCount();
对于(inti=1;i这里是我的改进版getColIdxByName,以支持MySQL 5.x名称,如“tbl.column”:
private int getColIdxByName(字符串名)引发SQLException{
RowSetMD=(RowSetMetaDataImpl)this.getMetaData();
int cols=RowSetMD.getColumnCount();
对于(inti=1;i最新的JDK1.7已经实现了CachedRowSet,标签名bug已经修复
import java.sql.ResultSet;
import javax.sql.rowset.CachedRowSet;
import javax.sql.rowset.RowSetFactory;
import javax.sql.rowset.RowSetProvider;
ResultSet rs = con.prepareStatement("SELECT r.UID AS R FROM r").executeQuery();
RowSetFactory rowSetFactory = RowSetProvider.newFactory();
CachedRowSet crs = rowSetFactory.createCachedRowSet();
crs.populate(rs);
您可以使用内部选择:
ResultSet rs = con.prepareStatement("SELECT * FROM (SELECT r.UID AS R FROM r) AA").executeQuery();
CachedRowSetImpl rslt = new CachedRowSetImpl();
rslt.populate(rs);
System.out.println(rslt.getMetaData().getColumnLabel(1));
rslt.next();
System.out.println(rslt.getString("R"));
一种解决方法似乎是将列包装在函数或数学运算中。然后可以在CachedRowSetImpl
中使用别名
如果您的SQL是这样的:
SELECT
id AS student_id,
cost - discount AS total_cost,
first_name AS name
FROM
students
您可以引用studentRow.getBigDecimal(“总成本”)
,但studentRow.getLong(“学生id”)
和studentRow.getString(“名称”)
将失败,并出现SQLException
“无效列名”
但是如果您的SQL是这样的:
SELECT
id + 0 AS student_id,
cost - discount AS total_cost,
CONCAT(first_name) AS name
FROM
students
然后它会像你所期望的那样工作
我不确定这会对性能造成什么样的损失,但它会在紧要关头起作用。在Netbeans中,我得到InvalidResultSetAccessException,在尝试创建新的ResultSetRappingSqlRowset(crs)时无法转换为throwable,其中crs是一个CachedRowSetIml。throws子句和try-catch都失败了。您能提出一些建议吗?对于第一个变体,您如何进行crs.populate(rs);如果没有看到填充方法,尽管它是从CachedRowSetImpl扩展而来的?@ZonResultSetRappingSqlRowset
可以-据我所知-只包装一个普通的ResultSet
。你应该使用它而不是CachedRowSetImpl
,而不是包装一个CachedRowSetImpl
(这也会破坏包装的目的,因为已经太晚了).至于您的第二个问题:该方法存在于超类中,因此您应该能够调用它。在Java 7上不起作用-仍然是列名,没有列标签。这只是给了我一个错误Table'.AA'。我的PreparedStatement
和ResultSet
工作正常。
SELECT
id AS student_id,
cost - discount AS total_cost,
first_name AS name
FROM
students
SELECT
id + 0 AS student_id,
cost - discount AS total_cost,
CONCAT(first_name) AS name
FROM
students