1

I am attempting to populate a jTable from a resultSet using SQLServer with the MS Driver 3.0.

The table will generate as long as I do not close the resultset, statement or connection. If I close them, then my table replies back with the message:

com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed.

I attempted to create my tablemodel using the "How to use Tables" tutorial.

Here is my Table Model:

TableModel model = new AbstractTableModel() {
                private String[] columnName = {"Employee ID", "Job Start", "Job ID",     "Oper. ID", "Indir. ID"};

            public int getColumnCount() {
                return columns;
            }

            public int getRowCount() {
                return rows;
            }

            public Object getValueAt(int row, int col) {
                try {
                    rs.absolute(row+1);
                    return rs.getObject(col+1);
                } catch (SQLException ex) {
                    System.err.println(ex);
                }
                return null;

            }
            public String getColumnName(int col) {
                return columnName[col];
            }
        };

My connections were originally done in a try with resources block, but in trying to find the issue I put it into a try-catch-finally block with the rs.close(), stmt.close(), and connection.close(). As I mentioned above, it will work fine if I do not have the close statements, but if I have them, then it states that the resultset is closed by the time it gets to the getValueAt method in my Table Model.

My whole code is here:

package dashboard;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import org.omg.CORBA.DATA_CONVERSION;


public class Dashboard extends JFrame {



      ResultSet rs;
        Connection connection;
    Statement stmt;
    ResultSetMetaData md;
    JScrollPane scrollpane;
    int columns, rows;
    JFrame frame;
    String connectionUrl;

    @SuppressWarnings("empty-statement")
    public Dashboard() throws SQLException {


        try {
            connection = DriverManager.getConnection(connectionUrl);
            stmt = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
            rs = stmt.executeQuery(query);

            ResultSetMetaData md = rs.getMetaData();

            //Count number of rows
            rs.last();
            rows = rs.getRow();
            rs.first();

            //Get column Count
            columns = md.getColumnCount();



            TableModel model = new AbstractTableModel() {
                private String[] columnName = {"Employee ID", "Job Start", "Job ID", "Oper. ID", "Indir. ID"};

                public int getColumnCount() {
                    return columns;
                }

                public int getRowCount() {
                    return rows;
                }

                public Object getValueAt(int row, int col) {
                    try {
                        rs.absolute(row+1);
                        return rs.getObject(col+1);
                    } catch (SQLException ex) {
                        System.err.println(ex);
                    }
                    return null;

                }
                public String getColumnName(int col) {
                    return columnName[col];
                }
            };


            JTable table = new JTable(model);
            table.setAutoCreateRowSorter(true);

            scrollpane = new JScrollPane(table);
            getContentPane().add(scrollpane);

            frame = new JFrame();
            frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
            frame.pack();
            frame.setTitle("Employee Dashboard");
            frame.setBounds(300, 300, 1300, 750);
            frame.setResizable(false);
            frame.add(scrollpane);
            frame.setVisible(true);
        } catch (SQLException ex) {
            System.err.println(ex);
        } finally {
            rs.close();
            stmt.close();
            connection.close();
        }

    }

    public static void main(String[] args) throws InterruptedException, SQLException {

        Dashboard me = new Dashboard();

    }
}

Update 6-4-13

I ended up tossing everything out and starting from scratch based on what @Reimeus said. I am not positive, but I think this is working. When I out print model.getRowCount() it tells me that it has the same rows as my query. The code is here:

 DefaultTableModel model = new DefaultTableModel();

        ResultSetMetaData meta = rs.getMetaData();
        int numberOfColumns = meta.getColumnCount();
        while (rs.next()) {
            Object[] rowData = new Object[numberOfColumns];
            for (int i = 0; i < rowData.length; ++i) {
                rowData[i] = rs.getObject(i + 1);

            }
            model.addRow(rowData);
            System.out.println(model.getColumnName(1));

        }

The issue I am having now is that I cannot generate a table with the table model. Here is what I thought would have worked:

 JTable table = new JTable(model);
        table.setAutoCreateRowSorter(true);

        scrollpane = new JScrollPane(table);
        getContentPane().add(scrollpane);

        frame = new JFrame();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.add(scrollpane);
        frame.setVisible(true);

In my mind I am thinking:

DB to RS RS to Table Model TM to Table Table to ScrollPane ScrollPane to Jtable

I am sure it is something dumb that I am doing but I am still not knowledgeable enough to recognize it yet.

Prizz
  • 57
  • 1
  • 1
  • 8
  • 3
    This is behaving as expected. What is the question? – Reimeus May 21 '13 at 20:31
  • Jeez, I was so nervous to post here that I actually forgot to ask any sort of question. My question is, why is my resultset closing before my getValueAt method? I have been looking at different examples over the last few days, and have been trying to use those as examples of how to do mine. I had it working with vectors just fine, but then I found out vectors were deprecated, and now I gotten to where I know that my resultset contains the data, I just want to put it into the table. In my mind this makes sense, but I am definitely a beginner and have come here as a last resort. – Prizz May 21 '13 at 20:45

1 Answers1

3

The ResultSet is closed when TableModel#getValueAt is invoked as Swing uses an event model to retieve the elements from TableModel. This occurs asynchronously, i.e. not on the main UI thread. Don't leave database resources such as Statement and ResultSet open. These create an overhead on the database itself.

Update the TableModel based on JDBC queries then close the associated database resources. Don't use ResultSet methods for populating the model.

Have a look at Creating a Table Model. It shows how fixed backing data is used to hold the data for the TableModel. Alternatively an ArrayList may be used.

If you're starting out, DefaultTableModel is easy to use and is mutable. Later you can progress to managing the update of the model such as in this example from @mKorbel

Aside: Use PreparedStatement rather than Statement to protect against SQL Injection attacks

Community
  • 1
  • 1
Reimeus
  • 158,255
  • 15
  • 216
  • 276
  • I will research PreparedStatements and make sure I use them in lieu of Statements. Concerning my error, your explanation makes perfect sense why it is closed. I understand that now. Thank you. You mention "Update the TableModel based on JDBC queries". Do you by chance have any suggestions on where I can learn more about how to update the Table Model using JDBC like you are suggesting? I would like to do this right and effectively, and it is obvious that the resources I am currently using are not leading me down the correct path. – Prizz May 21 '13 at 21:26
  • I will take a look at what you have suggested tomorrow and I will see if I can get it working. – Prizz May 21 '13 at 22:58
  • I think I cannot see the forest for the trees. I may be making this much more complicated than it needs to be. As I understand it currently: database->ResultSet->TableModel->Table. Is that the right way to do it, or am I missing/adding a step? If this is the correct way, then it seems my trouble is in getting the result set into the table model correctly. My end goal is a table that refreshes every x amount of time to reflect whether people have clocked in or out. Am I even approaching this the right way? – Prizz May 23 '13 at 18:17
  • Yes, just update the `TableModel` when required but don't use the `ResultSet` from within model itself. `DefaultTableModel` is easy when starting out. – Reimeus May 23 '13 at 18:21