libreria etiquetas etiqueta ejemplos java sql jdbc resultset

java - etiquetas - cachedrowsetimpl getString basado en la etiqueta de la columna



libreria de etiquetas jsp (5)

En el nombre de Dios
Zalema,

Tengo un problema. Cuando ejecuto un código de seguimiento, todo está bien:

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"));

y el resultado será:

R 23

pero cuando ejecuto el código siguiente, veo algunas cosas diferentes:

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"));

y el resultado será:

R java.sql.SQLException: Invalid column name

¿Alguien puede ayudarme, por favor?


¡el último JDK 1.7 ya implementó CachedRowSet y se ha corregido el error del nombre de la etiqueta!

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);


Aquí mi versión mejorada de getColIdxByName para soportar nombres de MySQL 5.x como "tbl.column":

private int getColIdxByName(String name) throws SQLException { RowSetMD = (RowSetMetaDataImpl) this.getMetaData(); int cols = RowSetMD.getColumnCount(); for (int i = 1; i <= cols; ++i) { String colLabel = RowSetMD.getColumnLabel(i); String colName = RowSetMD.getColumnName(i); if (colName != null) if (name.equalsIgnoreCase(colName) || name.equalsIgnoreCase(RowSetMD.getTableName(i) + "." + colName)) { return (i); } else if (colLabel != null) if (name.equalsIgnoreCase(colLabel)) { return (i); } else continue; } throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalcolnm").toString()); }


El problema es que la implementación de referencia de CachedRowSet ( com.sun.rowset.CachedRowSetImpl ) contiene un error: cuando recupera una columna por nombre, utiliza el columnName , y no el columnLabel , por lo que va contra el resto de la especificación JDBC que usa columnLabel para recuperar valores. Este error hace que sea imposible recuperar valores del conjunto de filas mediante columnLabel .

El error en Oracle es http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7046875 , pero (sorpresa, sorpresa) lo han hecho no disponible para su consulta pública.

Hay dos posibles soluciones. Una de ellas es comprobar si el controlador proporciona una propiedad para que también el método ResultSetMetaData.getColumnName(..) devuelva el valor de columnLabel , la segunda solución sería crear una subclase de CachedRowSetImpl (que, lamentablemente, requiere muchos métodos de anulación).

La siguiente versión se copia de este mensaje: http://tech.groups.yahoo.com/group/Firebird-Java/message/10715

import java.math.BigDecimal; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Ref; import java.sql.SQLException; import java.util.Calendar; import java.util.Collection; import java.util.Hashtable; import javax.sql.rowset.RowSetMetaDataImpl; import com.sun.rowset.CachedRowSetImpl; public class FixedCachedRowSetImpl extends CachedRowSetImpl { private static final long serialVersionUID = -9067504047398250113L; private RowSetMetaDataImpl RowSetMD; public FixedCachedRowSetImpl() throws SQLException { super(); } public FixedCachedRowSetImpl(Hashtable env) throws SQLException { super(env); } private int getColIdxByName(String name) throws SQLException { RowSetMD = (RowSetMetaDataImpl) this.getMetaData(); int cols = RowSetMD.getColumnCount(); for (int i = 1; i <= cols; ++i) { String colName = RowSetMD.getColumnLabel(i); if (colName != null) if (name.equalsIgnoreCase(colName)) return (i); else continue; } throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalcolnm").toString()); } @Override public Collection<?> toCollection(String column) throws SQLException { return toCollection(getColIdxByName(column)); } @Override public String getString(String columnName) throws SQLException { return getString(getColIdxByName(columnName)); } @Override public boolean getBoolean(String columnName) throws SQLException { return getBoolean(getColIdxByName(columnName)); } @Override public byte getByte(String columnName) throws SQLException { return getByte(getColIdxByName(columnName)); } @Override public short getShort(String columnName) throws SQLException { return getShort(getColIdxByName(columnName)); } @Override public int getInt(String columnName) throws SQLException { return getInt(getColIdxByName(columnName)); } @Override public long getLong(String columnName) throws SQLException { return getLong(getColIdxByName(columnName)); } @Override public float getFloat(String columnName) throws SQLException { return getFloat(getColIdxByName(columnName)); } @Override public double getDouble(String columnName) throws SQLException { return getDouble(getColIdxByName(columnName)); } @Override public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { return getBigDecimal(getColIdxByName(columnName), scale); } @Override public byte[] getBytes(String columnName) throws SQLException { return getBytes(getColIdxByName(columnName)); } @Override public java.sql.Date getDate(String columnName) throws SQLException { return getDate(getColIdxByName(columnName)); } @Override public java.sql.Time getTime(String columnName) throws SQLException { return getTime(getColIdxByName(columnName)); } @Override public java.sql.Timestamp getTimestamp(String columnName) throws SQLException { return getTimestamp(getColIdxByName(columnName)); } @Override public java.io.InputStream getAsciiStream(String columnName) throws SQLException { return getAsciiStream(getColIdxByName(columnName)); } @Override public java.io.InputStream getUnicodeStream(String columnName) throws SQLException { return getUnicodeStream(getColIdxByName(columnName)); } @Override public java.io.InputStream getBinaryStream(String columnName) throws SQLException { return getBinaryStream(getColIdxByName(columnName)); } @Override public Object getObject(String columnName) throws SQLException { return getObject(getColIdxByName(columnName)); } @Override public int findColumn(String columnName) throws SQLException { return getColIdxByName(columnName); } @Override public java.io.Reader getCharacterStream(String columnName) throws SQLException { return getCharacterStream(getColIdxByName(columnName)); } @Override public BigDecimal getBigDecimal(String columnName) throws SQLException { return getBigDecimal(getColIdxByName(columnName)); } @Override public boolean columnUpdated(String columnName) throws SQLException { return columnUpdated(getColIdxByName(columnName)); } @Override public void updateNull(String columnName) throws SQLException { updateNull(getColIdxByName(columnName)); } @Override public void updateBoolean(String columnName, boolean x) throws SQLException { updateBoolean(getColIdxByName(columnName), x); } @Override public void updateByte(String columnName, byte x) throws SQLException { updateByte(getColIdxByName(columnName), x); } @Override public void updateShort(String columnName, short x) throws SQLException { updateShort(getColIdxByName(columnName), x); } @Override public void updateInt(String columnName, int x) throws SQLException { updateInt(getColIdxByName(columnName), x); } @Override public void updateLong(String columnName, long x) throws SQLException { updateLong(getColIdxByName(columnName), x); } @Override public void updateFloat(String columnName, float x) throws SQLException { updateFloat(getColIdxByName(columnName), x); } @Override public void updateDouble(String columnName, double x) throws SQLException { updateDouble(getColIdxByName(columnName), x); } @Override public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException { updateBigDecimal(getColIdxByName(columnName), x); } @Override public void updateString(String columnName, String x) throws SQLException { updateString(getColIdxByName(columnName), x); } @Override public void updateBytes(String columnName, byte x[]) throws SQLException { updateBytes(getColIdxByName(columnName), x); } @Override public void updateDate(String columnName, java.sql.Date x) throws SQLException { updateDate(getColIdxByName(columnName), x); } @Override public void updateTime(String columnName, java.sql.Time x) throws SQLException { updateTime(getColIdxByName(columnName), x); } @Override public void updateTimestamp(String columnName, java.sql.Timestamp x) throws SQLException { updateTimestamp(getColIdxByName(columnName), x); } @Override public void updateAsciiStream(String columnName, java.io.InputStream x, int length) throws SQLException { updateAsciiStream(getColIdxByName(columnName), x, length); } @Override public void updateBinaryStream(String columnName, java.io.InputStream x, int length) throws SQLException { updateBinaryStream(getColIdxByName(columnName), x, length); } @Override public void updateCharacterStream(String columnName, java.io.Reader reader, int length) throws SQLException { updateCharacterStream(getColIdxByName(columnName), reader, length); } @Override public void updateObject(String columnName, Object x, int scale) throws SQLException { updateObject(getColIdxByName(columnName), x, scale); } @Override public void updateObject(String columnName, Object x) throws SQLException { updateObject(getColIdxByName(columnName), x); } @Override public Object getObject(String columnName, java.util.Map<String, Class<?>> map) throws SQLException { return getObject(getColIdxByName(columnName), map); } @Override public Ref getRef(String colName) throws SQLException { return getRef(getColIdxByName(colName)); } @Override public Blob getBlob(String colName) throws SQLException { return getBlob(getColIdxByName(colName)); } @Override public Clob getClob(String colName) throws SQLException { return getClob(getColIdxByName(colName)); } @Override public Array getArray(String colName) throws SQLException { return getArray(getColIdxByName(colName)); } @Override public java.sql.Date getDate(String columnName, Calendar cal) throws SQLException { return getDate(getColIdxByName(columnName), cal); } @Override public java.sql.Time getTime(String columnName, Calendar cal) throws SQLException { return getTime(getColIdxByName(columnName), cal); } @Override public java.sql.Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException { return getTimestamp(getColIdxByName(columnName), cal); } @Override public void updateRef(String columnName, java.sql.Ref ref) throws SQLException { updateRef(getColIdxByName(columnName), ref); } @Override public void updateClob(String columnName, Clob c) throws SQLException { updateClob(getColIdxByName(columnName), c); } @Override public void updateBlob(String columnName, Blob b) throws SQLException { updateBlob(getColIdxByName(columnName), b); } @Override public void updateArray(String columnName, Array a) throws SQLException { updateArray(getColIdxByName(columnName), a); } @Override public java.net.URL getURL(String columnName) throws SQLException { return getURL(getColIdxByName(columnName)); } }

También puede consultar org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet , que también dice:

Nota: desde JDBC 4.0, se ha aclarado que cualquier método que use una cadena para identificar la columna debe usar la etiqueta de la columna. La etiqueta de la columna se asigna con la palabra clave ALIAS en la cadena de consulta SQL. Cuando la consulta no utiliza un ALIAS, la etiqueta predeterminada es el nombre de la columna. La mayoría de las implementaciones de ResultSet de JDBC siguen este nuevo patrón, pero existen excepciones como la clase com.sun.rowset.CachedRowSetImpl que solo utiliza el nombre de columna, ignorando las etiquetas de columna. A partir de Spring 3.0.5, ResultSetWrappingSqlRowSet traducirá las etiquetas de las columnas al índice de columnas correcto para proporcionar una mejor compatibilidad con com.sun.rowset.CachedRowSetImpl que es la implementación predeterminada utilizada por JdbcTemplate cuando se trabaja con RowSets.


Puede usar la selección interna:

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"));


Una solución alternativa parece ser envolver sus columnas en una función u operación matemática. Luego puede usar el alias en CachedRowSetImpl .

Si tu SQL es este:

SELECT id AS student_id, cost - discount AS total_cost, first_name AS name FROM students

Podrá referirse a studentRow.getBigDecimal("total_cost") , pero studentRow.getLong("student_id") y studentRow.getString("name") fallará con una SQLException "Invalid column name".

Pero si tu SQL fue así:

SELECT id + 0 AS student_id, cost - discount AS total_cost, CONCAT(first_name) AS name FROM students

Entonces funciona como era de esperar.

No estoy seguro de cuál sería la penalización de rendimiento para esto, pero funcionará en caso de apuro.