优化 JDBC 中对 JTable 的数据调用
Posted
技术标签:
【中文标题】优化 JDBC 中对 JTable 的数据调用【英文标题】:Optimize data calling in JDBC onto JTable 【发布时间】:2015-01-18 21:02:51 【问题描述】:目前我在 mysql 服务器中有数据,我正在通过 JDBC 将数据调用到 JTable 上。但是有 1369 行,并且它似乎有太多数据无法加载。加载通常需要 5 分钟。有什么办法可以优化流程吗?这是我的代码(我提前为混乱的代码道歉):
public class DataTable
private String databaseName = "*****";
private String tableName = "******";
public void showDatabase()
Connection conn = null;
DatabaseMetaData meta = null;
Statement stmt = null;
ResultSet rs = null;
int k = 0;
try
Class.forName("com.mysql.jdbc.Driver").newInstance();
String connectionUrl = "jdbc:mysql://localhost:3306/" + databaseName;
String connectionUser = "*****";
String connectionPassword = "*****";
conn = DriverManager.getConnection(connectionUrl, connectionUser, connectionPassword);
stmt = conn.createStatement();
meta = conn.getMetaData();
dataSets(stmt, meta);
catch(Exception e)
e.printStackTrace();
finally
try if (rs != null) rs.close(); catch (SQLException e) e.printStackTrace();
try if (stmt != null) stmt.close(); catch (SQLException e) e.printStackTrace();
try if (conn != null) conn.close(); catch (SQLException e) e.printStackTrace();
//return the column size of the table
public int getColumnNumber(DatabaseMetaData meta, Statement stmt) throws SQLException
//ResultSet rs = meta.getColumns(null, null, "practiceexample", null);
ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName);
ResultSetMetaData rsmd = rs.getMetaData();
int columnsNumber = rsmd.getColumnCount();
return columnsNumber;
//return the rowNumber of the tables
public int getRowNumber(Statement stmt) throws SQLException
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
int rowCount = 0;
while(rs.next())
rowCount = rs.getInt(1);
return rowCount;
public void dataSets(Statement stmt, DatabaseMetaData meta) throws SQLException
String[] columnNames = new String[getColumnNumber(meta, stmt)];
String[][] dataSets = new String[getRowNumber(stmt)][columnNames.length];
ResultSet column = meta.getColumns(null, null, tableName, null);
int i = 0;
while(column.next())
columnNames[i] = column.getString("COLUMN_NAME");
//columnNames.add(i, column.getString("COLUMN_NAME"));
i++;
for(int j = 0; j < dataSets.length; j++)
String[] singleRowData = new String[columnNames.length];
ResultSet data = null;
for(int k = 0; k < columnNames.length; k++)
String columnName = columnNames[k];
data = stmt.executeQuery("SELECT " + columnName +
" FROM " + tableName + " LIMIT " + j + ", " + 1);
while(data.next())
singleRowData[k] = data.getString(columnName);
dataSets[j] = singleRowData;
SimpleTable table = new SimpleTable(columnNames, dataSets);
javax.swing.SwingUtilities.invokeLater(new Runnable()
public void run()
table.createAndShowGUI();
);
class SimpleTable
String[] columns;
String[][] dataSets;
public SimpleTable(String[] columns, String[][] dataSets)
this.columns = columns;
this.dataSets = dataSets;
public void createAndShowGUI()
JPanel gui = new JPanel(new BorderLayout(3, 3));
final JTable table = new JTable(new DefaultTableModel(dataSets, columns));
final JScrollPane scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
Dimension dimension = table.getPreferredSize();
scrollPane.setPreferredSize(new Dimension(dimension.width, table.getRowHeight() * 30));
JPanel navigation = new JPanel(new FlowLayout(FlowLayout.CENTER));
JButton next = new JButton(">");
next.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent e)
int height = table.getRowHeight() * (20-1);
JScrollBar bar = scrollPane.getVerticalScrollBar();
bar.setValue(bar.getValue() + height);
);
JButton previous = new JButton("<");
previous.addActionListener( new ActionListener()
public void actionPerformed(ActionEvent ae)
int height = table.getRowHeight()*(20-1);
JScrollBar bar = scrollPane.getVerticalScrollBar();
bar.setValue( bar.getValue()-height );
);
navigation.add(previous);
navigation.add(next);
gui.add(scrollPane, BorderLayout.CENTER);
gui.add(navigation, BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null, gui);
【问题讨论】:
优化整个应用程序的一种方法是使用连接池,而不是手动创建物理数据库连接。这将极大地增强您的应用程序。 对不起,我还是新手,我不太确定连接池是什么。那是在 java 库中吗? 您可以使用SwingWorker
在后台加载数据并将更新推送到 UI。虽然它不会加快整个过程,但它会让你更早地呈现 UI,给人一种速度的错觉
这个example 可能会有所帮助。
感谢大家的帮助。我能弄明白!
【参考方案1】:
恕我直言,不良性能的根源是您不必要地多次查询数据库以获取所需的数据(列、行、行数、列数等):
获取列号:
ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName);
获取行号:
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
获取行(这是最糟糕的,因为它在循环中):
data = stmt.executeQuery("SELECT " + columnName + " FROM " + tableName + " LIMIT " + j + ", " + 1);
如何解决
只需查询一次数据库。单个ResultSet 及其关联的ResultSetMetaData 应该足以实现您的目标。另外,正如已经建议的那样,使用SwingWorker
在单独的线程中进行数据库调用。例如:
final JTable table = new JTable();
SwingWorker<Void, TableModel> worker = new SwingWorker<Void, TableModel> ()
@Override
protected Void doInBackground() throws Exception
ResultSet resultSet = stmt.executeQuery("SELECT * FROM " + tableName);
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount(); // columns number
String[] columnNames = new String[columnCount];
for (int i = 1; i <= columnCount; i++)
columnNames[i] = metaData.getColumnName(i); // fill columns names
resultSet.last();
int rowCount = resultSet.getRow(); // get rows number
resultSet.beforeFirst();
Object[][] data = new Object[rowCount][columnCount];
int currentRow = 0;
while (resultSet.next())
for (int currentColumn = 1; currentColumn <= columnCount; currentColumn++)
data[currentRow][currentColumn - 1] = resultSet.getObject(currentColumn); // fill data set
currentRow++;
TableModel model = new DefaultTableModel(data, columnNames);
publish(model);
return null;
@Override
protected void process(List<TableModel> chunks)
TableModel model = chunks.get(0);
table.setModel(model);
worker.execute();
【讨论】:
感谢您的回复。我已经尝试过了,它给了我一个错误,因为我需要返回 Void 类型的函数。我不知道为什么会这样。 其实我想通了!感谢您的帮助! 哦,我忘了return null
在doInBackground()
实现的末尾。这是因为 SwingWorkerdoInBackground()
方法返回的类型(根据合同它必须返回一些东西):这就是 V 的意思。此值可通过get()
方法在内部使用。 OTOH 参数 T 表示由publish
和process
方法管理的类。所以在这种情况下,您不必只返回 null
,因为从未使用过 get()
(很少使用)。 @Kito以上是关于优化 JDBC 中对 JTable 的数据调用的主要内容,如果未能解决你的问题,请参考以下文章
使用复杂的 TableCellRenderer 在 JTable 中格式化来自 JDBC 的数据
JT400 - IBMi 机器拒绝 JDBC 连接,但在 Windows 机器上工作