[Dúvida] - H2, inserindo linhas

Olá GUJ!

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.

Oi tondatto!

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?

Obrigado! :wink:

Oi litium.

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?

E aí tondatto!

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:

this.tabela.getColumnModel().getColumn(3).setPreferredWidth(60);

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

Obrigado de qualquer forma! :wink:

Nossa.

Ninguém tem nenhuma noção de como ajeitar isso? Tô querendo redimensionar a minha tabela para que ela fique apresentável na hora de sua visualização.

Grato desde sempre. :-o

Litium.

Pela descrição do erro, você está tentando acessar um método do JDBC depois de fechar os recursos.

TabelaModelo é seu TableModel? Tem como postar o método getColumnClass()?

Eu acho que você está tentando fechar o objeto duas vezes, só não consegui identificar se é um Connection, um Statment ou ResultSet

Oi Eric Yuzo.

Aqui vai o método que você pediu:

	@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.

O construtor dessa classe está desta forma:

public TabelaModelo(String driverJDBC , String dataBaseURL , String usuario , String senha)
	{
		try 
		{
			// Iniciando driver
			Class.forName(driverJDBC);
			
			// Iniciando conectividade com banco
			this.conection = DriverManager.getConnection(dataBaseURL , usuario , senha);
			
			// Iniciando Objeto Statement
			this.statement = this.conection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE , ResultSet.CONCUR_READ_ONLY);
			
			// Modifica estado de conexão com banco
			this.bancoConectado = true;
			
			// Insere consulta padrão da tabela
			this.setQuery("SELECT * FROM SERIAIS");
		} 
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		} 
		catch (SQLException e) 
		{
			e.printStackTrace();
		}
	}

Fiz algo simples, mas será que fiz errado? :frowning:

Litium.

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.

Oi Eric!

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.”?

Obrigado pela ajuda.

Litium.

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.