Bom, eu estou tendo problemas em inserir linhas em uma tabela usando o banco de dados H2. Estou até usando um exemplo do livro do Deitel. Ah, e isso não ocorre só quando vou inserir, mas quando vou criar tabelas também. Olha só o que acontece quando tento inserir algo:
org.h2.jdbc.JdbcSQLException: Method is only allowed for a query. Use execute or executeUpdate instead of executeQuery; SQL statement:
insert into pessoa (nome , idade) values ('teste2' , 12) [90002-153]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
at org.h2.message.DbException.get(DbException.java:167)
at org.h2.message.DbException.get(DbException.java:144)
at org.h2.message.DbException.get(DbException.java:133)
at org.h2.command.Prepared.query(Prepared.java:212)
at org.h2.command.CommandContainer.query(CommandContainer.java:78)
at org.h2.command.Command.executeQuery(Command.java:181)
at org.h2.jdbc.JdbcStatement.executeQuery(JdbcStatement.java:76)
at util.TabelaModelo.inserirConsulta(TabelaModelo.java:217)
at senac.SProgramas.actionPerformed(SProgramas.java:123)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Meu código para executar SQL está assim:
public void inserirConsulta(String query)
{
// Se estiver conectado ao banco
if(this.bancoConectado)
{
try
{
// Realiza consulta
this.resultSet = this.statement.executeQuery(query);
// Obtém meta dados
this.metaData = this.resultSet.getMetaData();
// Move cursor da "tabela" do objeto ResultSet para última linha
this.resultSet.last();
// Utiliza objeto ResultSet movido para última linha para adquirir número de linhas em tabela
this.linhas = this.resultSet.getRow();
// Notifica a JTable que está usando este modelo que o modelo foi alterado
this.fireTableStructureChanged();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
// Se não estiver
else
{
System.out.println("Banco de dados não conectado em método inserirConsulta() da classe TabelaModelo.");
throw new IllegalStateException();
}
}
Lá na guia de erros do H2, tem dizendo isso:
"METHOD_ONLY_ALLOWED_FOR_QUERY = 90002
The error with code 90002 is thrown when Statement.executeQuery() was called for a statement that does not return a result set (for example, an UPDATE statement). This is not allowed according to the JDBC specs."
Mas caramba, o executeQuery retorna um objeto ResultSet. O que devo fazer?
Você deve analisar a query antes de chamar o executeQuery.
Pois esta exception é disparada quanto o comando não retorna um ResultSet (ex., CREATE TABLE, UPDATE, INSERT não retornam).
Daí então, você pode chamar o método statement.executeQuery(query) sem necessariamente estar atribuindo valor a um ResultSet, ou seja, como se ele tivesse um retorno void.
Cara valeu pela dica, funcionou direitinho aqui. O que eu fiz foi usar o método Statement.execute() para executar as querys sem retorno como você me disse. Mas eu fiquei um pouco na dúvida ainda, eu devo usar o Statement.executeQuery() somente para fazer alguma consulta?
Como eu havia digo “Você deve analisar a query antes de chamar o executeQuery.”
Ou seja,
// se a 'query' em transformada em maiuscula inicia com "SELECT"
if(query.toUpperCase().startWith("SELECT"){
this.resultset = this.statement.executeQuery(query);
}else{
this.statement.executeQuery(query);
}Sacou?
Cara! Eu fiz exatamente isso! heheheheh! O que você falou me ajudou bastante. Tô deixando o meu código assim mesmo. Só que tem um probleminha… Toda vez que eu dou uma consulta select na janela de comando, a tabela muda como deve mudar, só que, a largura das colunas é sempre alterada para o tamanho inicial.
Ou seja, se eu faço a consulta, a tabela aparece dum jeito. Eu redimensiono algumas colunas e após fazer uma nova consulta, a tabela volta para as dimensões anteriores da que eu coloquei. Eu tentei fazer algo como:
E coloquei para que isso acontecesse sempre que eu clicasse no botão de executar query (dentro do ActionEvent). Mas aí, comecei a receber uma nova exception do programa:
org.h2.jdbc.JdbcSQLException: The object is already closed [90007-153]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
at org.h2.message.DbException.get(DbException.java:167)
at org.h2.message.DbException.get(DbException.java:144)
at org.h2.message.DbException.get(DbException.java:133)
at org.h2.jdbc.JdbcResultSet.checkClosed(JdbcResultSet.java:2929)
at org.h2.jdbc.JdbcResultSetMetaData.checkClosed(JdbcResultSetMetaData.java:418)
at org.h2.jdbc.JdbcResultSetMetaData.checkColumnIndex(JdbcResultSetMetaData.java:426)
at org.h2.jdbc.JdbcResultSetMetaData.getColumnClassName(JdbcResultSetMetaData.java:354)
at util.TabelaModelo.getColumnClass(TabelaModelo.java:141)
at javax.swing.JTable.getColumnClass(Unknown Source)
at javax.swing.JTable.getCellRenderer(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
at javax.swing.plaf.ComponentUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JViewport.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.BufferStrategyPaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
org.h2.jdbc.JdbcSQLException: The object is already closed [90007-153]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
at org.h2.message.DbException.get(DbException.java:167)
at org.h2.message.DbException.get(DbException.java:144)
at org.h2.message.DbException.get(DbException.java:133)
at org.h2.jdbc.JdbcResultSet.checkClosed(JdbcResultSet.java:2929)
at org.h2.jdbc.JdbcResultSet.absolute(JdbcResultSet.java:2592)
at util.TabelaModelo.getValueAt(TabelaModelo.java:115)
at javax.swing.JTable.getValueAt(Unknown Source)
at javax.swing.JTable.prepareRenderer(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
at javax.swing.plaf.ComponentUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JViewport.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.BufferStrategyPaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.JTable.prepareRenderer(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
at javax.swing.plaf.ComponentUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JViewport.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.BufferStrategyPaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Enorme, por certo. Eu procurei na lista de erros do H2 e diz isso aqui:
"OBJECT_CLOSED = 90007
The error with code 90007 is thrown when trying to call a JDBC method on an object that has been closed."
Não tenho a menor idéia do que isso quer dizer pois não tem nenhum objeto fechado (suponho que seja o Connection e o Statement).
@Override
public Class getColumnClass(int coluna)
{
// Se estiver conectado ao banco
if(this.bancoConectado)
{
try
{
String nomeDaClasse = this.metaData.getColumnClassName(coluna + 1);
return Class.forName(nomeDaClasse);
}
catch(Exception exception)
{
exception.printStackTrace();
}
return null;
}
// Se não estiver
else
{
System.out.println("Banco de dados não conectado em método getColumnClass() da classe TabelaModelo.");
throw new IllegalStateException();
}
}
E sim, minha TabelaModelo é uma classe que estende AbstractTableModel.
Então o erro diz que o objeto que está tentando usar já está fechado. Então, seguindo a stackTrace, chega neste método (getColumnClass):
at util.TabelaModelo.getColumnClass(TabelaModelo.java:141)Imagino que o objeto fechado seja este metadata:
String nomeDaClasse = this.metaData.getColumnClassName(coluna + 1);Confirme se esta não é a linha 141 da classe TabelaModelo.
O TableModel não deveria ficar executando operações no banco dentro de seus métodos. Se precisa carregar os nomes das colunas por metadados, talvez seja melhor fazer a consulta e carregar as classes das colunas em um array ou em uma lista e, no método getColumnClass, só retornar o objeto do índice especificado.
Rapaz, esta é exatamente a linha de minha classe TabelaModelo. Mas… eu só estou tentando reajustar a largura de minhas colunas em minha JTable. Preciso estar conectado ao banco de dados para realizar tal procedimento?
Pelo que eu entendi, você está sugerindo que eu não coloque métodos de conexão e manipulação com o banco de dados na mesma classe de minha TableModel? E como assim “talvez seja melhor fazer a consulta e carregar as classes das colunas em um array ou em uma lista e, no método getColumnClass, só retornar o objeto do índice especificado.”?
A questão é que quando redimensiona a coluna, a JTable tem que se repintar na tela, no processo ela acaba chamando o getColumnClass, que acessa o metadata para pegar o tipo da coluna. Procure pelo stacktrace que vai achar.
at util.TabelaModelo.getColumnClass(TabelaModelo.java:141)
at javax.swing.JTable.getColumnClass(Unknown Source)
at javax.swing.JTable.getCellRenderer(Unknown Source)
Vou deixar uma ideia. Ao invés de usar diretamente o metadata para recuperar o tipo da classe no getColumnClass, pode fazer um laço e guardar os tipos das colunas em um array (isso antes de instanciar o TableModel). No getColumnClass, pega retorna o índice a partir do array, assim não precisa acessar o metadata.