【发布时间】:2019-07-05 19:41:48
【问题描述】:
我正在尝试创建一个框架来显示我的数据库中的所有电影名称,然后他们选择框架中的一行来执行另一个查询。
我有一个 ResultSet (rs),它接收查询执行的结果以选择电影的名称。之后,我在我的 SQLTableModel 中使用 rs 来创建 JTable 并显示在我的框架中。该表显示了我数据库中所有电影的名称。一切都很好。
但是,当我选择一行时,我使用相同的 rs 接收另一个查询,该查询在我的数据库中选择我在 JTable 中选择的电影的所有信息,我得到了一些错误。
首先,我在 JTable 中选择的行丢失了值(电影的名称)。但在其他行中没有发生任何事情。 其次,我的控制台向我显示了一个来自我的 SQLTableModel 的错误,在函数“getValueAt”中,说“Erro: #0 Operation not allowed after ResultSet closed”。
我在stackoverflow中搜索了一些解决方案,但没有成功。
我做了一些测试。如果我的 ResultSet (rs) 在我在 SQLTableModel 中使用它之前收到多个查询,那么一切正常。但是当我在 SQLTableModel 中使用它之后,如果我再次尝试使用它,就会得到我提到的错误。
FrameCliente.java
public class FrameCliente {
JFrame frameCliente;
JTable table;
BancoDeDados bd;
ResultSet rs;
public FrameCliente() {
bd = new BancoDeDados();
frameCliente = new JFrame();
table = new JTable();
rs = bd.listar("SELECT fil_nome Nome FROM filme");
table.setModel(new SQLTableModel(rs));
table.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if(table.getSelectedRowCount() > 0) {
rs = bd.listar(" SELECT * FROM filme WHERE fil_nome = '" + table.getValueAt(table.getSelectedRow(), 0) + "'");
}
}
});
frameCliente.add(new JScrollPane(table));
frameCliente.setTitle("Filmes");
frameCliente.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frameCliente.setSize(800, 300);
frameCliente.setLocationRelativeTo(null);
frameCliente.setVisible(true);
}
}
SQLTableModel.java
public class SQLTableModel extends AbstractTableModel {
private ResultSet rs;
private ResultSetMetaData rsmd;
private int numberOfRows=0;
public SQLTableModel(ResultSet rs){
this.rs = rs;
try { //Todos os métodos são privado e isso gera exceção.
rsmd = this.rs.getMetaData();
//Navegar para encontrar a ultima linha, para saber quantas linhas a tabela possui.
this.rs.last(); // Pega a ultima linha;
numberOfRows = rs.getRow(); //Devolve a linha, no caso, a ultima.
this.rs.beforeFirst(); //Retorna para a primeira linha.
}catch(SQLException sqle){
System.out.printf("Erro: #%d [%s]\n",
sqle.getErrorCode(), sqle.getMessage());
}
}
@Override
public int getRowCount() {
// TODO Auto-generated method stub
return numberOfRows;
}
@Override
public int getColumnCount() {
// TODO Auto-generated method stub
try {
return rsmd.getColumnCount();
}catch(SQLException sqle){
System.out.printf("Erro: #%d [%s]\n",
sqle.getErrorCode(), sqle.getMessage());
return 0; // Se der exceção não retorna nenhuma coluna;
}
}
@Override
public String getColumnName(int column) {
String ColumnName = "";
try {
ColumnName = rsmd.getColumnLabel(column+1);
}catch(SQLException sqle){
System.out.printf("Erro: #%d [%s]\n",
sqle.getErrorCode(), sqle.getMessage());
}
return ColumnName;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
// TODO Auto-generated method stub
Object dado = null;
try {
rs.absolute(rowIndex+1);
dado = rs.getObject(columnIndex+1);
}catch(SQLException sqle){
System.out.printf("Erro: #%d [%s]\n",
sqle.getErrorCode(), sqle.getMessage());
}
return dado;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
String className;
try {
className = rsmd.getColumnClassName(columnIndex+1);
return Class.forName(className);
}catch(SQLException sqle){
System.out.printf("Erro: #%d [%s]\n",
sqle.getErrorCode(), sqle.getMessage());
} catch (ClassNotFoundException cnfe) {
System.out.printf("Erro: %s\n", cnfe.getMessage());
}
return null;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
public void atualizarTabela() {
fireTableDataChanged();
}
}
BancoDeDados
public class BancoDeDados {
private Connection con = null;
private Statement sta = null; //faz consultas
private ResultSet rset = null; //armazenas as info pra trabalhar com elas depois - resultado do select
public BancoDeDados() {
this.conectar();
}
public void conectar() {
String servidor = "jdbc:mysql://localhost:3306/cinema?useSSL=true&useTimezone=true&serverTimezone=UTC";
String usuario = "root";
String senha = "coreduo2";
String driver = "com.mysql.cj.jdbc.Driver";
try {
//Class.forName(driver);
this.con = DriverManager.getConnection(servidor, usuario, senha);
this.sta = this.con.createStatement();
}
catch(Exception e)
{
System.out.println("Error " + e.getMessage());
}
}
public boolean estaConectado() {
if (con != null) {
return true;
}
else {
return false;
}
}
public void desconecte() {
try {
con.close();
System.out.println("Conexao com banco encerrado");
}
catch(SQLException e) {
System.out.println("Erro: " + e.getMessage());
}
}
public ResultSet listar(String query) {
try {
return sta.executeQuery(query);
//this.sta = this.con.createStatement();
/*while (this.rset.next()) {
System.out.println("ID: " + rset.getString("fil_codigo") + " Nome: " + rset.getString("fil_nome") + " Duração: " + rset.getString("fil_duracao"));
}*/
}
catch(SQLException e) {
System.out.println("Erro "+ e.getMessage());
return null;
}
}
public void inserir(String query) {
try {
this.sta.executeUpdate(query);
}
catch(SQLException e) {
System.out.println("Erro"+ e.getMessage());
}
}
public void excluir(String query) {
try {
this.sta.executeUpdate(query);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void editar(String query) {
try {
this.sta.executeUpdate(query);
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
【问题讨论】:
-
Statements 和ResultSets 应该具有最小范围(通常是方法的本地),并且应该使用“try-with-resources”语句正确关闭它们。您当前将这些存储为类的字段,这并不理想。您能否还指出您的代码中的确切位置出现错误? -
错误在 SQLTableModel.java 中,在函数“getValueAt”中。您是否有显示如何在 AbstractTableModel 中使用 Statement 和 ResultSet 的链接?
-
在您的
SQLTableModel.java课程中,我看不到您在哪里设置ResultSet rs字段? -
你不能这样做。您的
SQLTableModel基于ResultSet的整个想法是错误的。你不能让结果集像那样徘徊。使用集合。 -
明白。谢谢!!!
标签: java resultset tablemodel