将多个数据库表数据展示到JTable时遇到问题求助
问题描述
我接触Java+SQL开发时间不长,为实现“把多个数据库表数据展示到JTable”这个功能折腾了好几周,现在卡壳了——要么只能显示单个表,要么三个表的数据乱堆在一起,滚动面板的表头还会出现所有表的ID列,求方向上的指导。
代码核心问题分析
表格模型复用导致数据堆叠
你在循环创建表格时,复用了JTable默认的DefaultTableModel,没有每次循环都新建模型,之前表的数据会残留到下一个表的模型里,最终导致数据混乱堆叠。表头设置位置错误
把model.setColumnIdentifiers(colName);放在了列名遍历的内部,每遍历一列就设置一次表头,多次覆盖后表头会出现混乱。表名获取逻辑错误
使用mD.getTableName(k+1)获取表名是错误的,循环索引k和ResultSetMetaData中列对应的表索引没有关联,会导致标签页名称错误。
修正后的关键代码
1. 修改getData方法,同时存储表名和数据
将原本只存CachedRowSet的集合,改成同时存储表名和对应数据,避免后续获取表名出错:
public static ArrayList<Map<String, Object>> getData(String url, String database, String user, String pass) { PreparedStatement stat, stat2; ResultSet data, dbName; String dbURLString = "jdbc:mysql://" + url + "/" + database; String dbSql = "Show tables from " + database; String sqlState; ArrayList<Map<String, Object>> dataList = new ArrayList<>(); try { Class.forName("com.mysql.cj.jdbc.Driver"); try (Connection conn = DriverManager.getConnection(dbURLString, user, pass)) { stat = conn.prepareStatement(dbSql); dbName = stat.executeQuery(); while (dbName.next()) { RowSetFactory fact = RowSetProvider.newFactory(); CachedRowSet crs = fact.createCachedRowSet(); String tableName = dbName.getString("Tables_in_" + database); sqlState = "Select * from " + tableName + ";"; stat2 = conn.prepareStatement(sqlState); data = stat2.executeQuery(); crs.populate(data); // 封装表名和对应数据 Map<String, Object> tableData = new HashMap<>(); tableData.put("tableName", tableName); tableData.put("data", crs); dataList.add(tableData); } conn.close(); loginButton.Instance.dispose(); return dataList; } } catch (SQLException | ClassNotFoundException ex) { Logger.getLogger(DatabaseSchema2.class.getName()).log(Level.SEVERE, "Failed to get data", ex); loginButton.Instance.errLabel.setVisible(true); } return null; }
2. 修改addPane方法,正确创建独立的表格和模型
每次循环都新建DefaultTableModel,确保每个表的数据和表头独立:
public static JTabbedPane addPane() throws SQLException { String user = loginButton.Instance.username; String pass = loginButton.Instance.password; String url = loginButton.Instance.server; String database = loginButton.Instance.database; JTabbedPane pane = new JTabbedPane(JTabbedPane.TOP); ArrayList<Map<String, Object>> dataList = getData(url, database, user, pass); if(dataList == null || dataList.isEmpty()){ return pane; } for (Map<String, Object> tableData : dataList) { String tableName = (String) tableData.get("tableName"); CachedRowSet data = (CachedRowSet) tableData.get("data"); // 每次循环新建模型,避免数据污染 DefaultTableModel model = new DefaultTableModel(); JTable table = new JTable(model); JScrollPane scroll = new JScrollPane(table); ResultSetMetaData mD = data.getMetaData(); int columns = mD.getColumnCount(); String[] colName = new String[columns]; // 先遍历获取所有列名 for (int j = 0; j < columns; j++) { colName[j] = mD.getColumnName(j + 1); } // 统一设置表头 model.setColumnIdentifiers(colName); // 添加数据行 while (data.next()) { ArrayList<String> rows = new ArrayList<>(); for (int i = 0; i < columns; i++) { String row = data.getString(i + 1); rows.add(row); } model.addRow(rows.toArray()); } pane.addTab(tableName, scroll); } return pane; }
额外优化建议
- 给JTable添加自动列宽调整:
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);,提升显示体验。 - 可以对
getString返回的null值做处理,比如替换成空字符串,避免表格显示null。
内容的提问来源于stack exchange,提问作者Michael Richards
相关产品推荐
相关产品推荐

