【问题标题】:Operation not allowed after ResultSet closed after using ResultSet in AbstractTableModel在 AbstractTableModel 中使用 ResultSet 后 ResultSet 关闭后不允许操作
【发布时间】: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


【解决方案1】:

始终使用 ArrayList 或 Map 等内存结构来缓存从 DB 获得的结果。由于与 DB 的连接很昂贵,因此保持这种连接也很昂贵。因此,尽可能快地调用 DB,尽可能短。一旦你在内存中获得数据,你就可以随意操作了。

【讨论】:

    猜你喜欢
    • 2012-06-11
    • 2017-04-17
    • 2018-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-02
    • 1970-01-01
    相关资源
    最近更新 更多