You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Swing中JTable无法实时显示MySQL新增数据的问题

问题分析与解决方案

问题原因

  1. ResultSet游标位置错误:在DatabaseConnector(String sqlQuery, JTable table)构造方法中,调用resultSet.next()判断结果集是否为空时,会将游标从初始的before first位置移动到第一行。而DbUtils.resultSetToTableModel(resultSet)会从当前游标位置读取数据,导致第一行数据被跳过(包括新增的记录)。
  2. TableRowSorter未同步:StaffLibraryTable初始化时给JTable绑定了TableRowSorter,新增数据后重新设置TableModel时,旧的排序器仍绑定原model,新model的变化无法同步到界面。
  3. 代码设计缺陷:DatabaseConnector的构造方法承担了连接、增删改、查询绑定等多重职责,逻辑混乱;同时使用String.format拼接SQL存在严重的SQL注入风险。

解决方案

1. 修复ResultSet游标问题

修改DatabaseConnector中绑定JTable的构造方法,使用可滚动ResultSet并避免提前移动游标:

public DatabaseConnector(String sqlQuery, JTable table) {
    try{
        Class.forName("com.mysql.cj.jdbc.Driver");
        connection = DriverManager.getConnection(url, uname, password);
        // 创建可滚动的ResultSet,避免游标移动导致数据丢失
        statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        resultSet = statement.executeQuery(sqlQuery);
        
        // 安全判断结果集是否为空,不移动游标
        if (!resultSet.isBeforeFirst()) {
            System.out.println("result set is empty");
        }
        
        tableModel = DbUtils.resultSetToTableModel(resultSet);
        table.setModel(tableModel);
    } catch (ClassNotFoundException | SQLException e) {
        System.out.println("error in DatabaseConnector(String sqlQuery, JTable table) - first part");
        System.out.println(e.getMessage());
    } finally {
        try {
            // 确保所有资源都被关闭
            if (resultSet != null) resultSet.close();
            if (statement != null) statement.close();
            if (connection != null) connection.close();
        } catch (SQLException e) {
            System.out.println("error in DatabaseConnector(String sqlQuery, JTable table) - second part");
            System.out.println(e.getMessage());
        }
    }
}

2. 重新绑定TableRowSorter

在新增数据后,重新创建并绑定排序器到新的TableModel:

addButton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // ... 原有输入校验逻辑 ...
        
        DatabaseConnector databaseConnector = new DatabaseConnector(sqlQuery);
        JOptionPane.showMessageDialog(null, "Dodano pracownika");
        
        // 清空输入框...
        
        // 刷新表格
        new DatabaseConnector("select * from stafflist", staffTable);
        // 重新绑定行排序器
        TableRowSorter<TableModel> newRowSorter = new TableRowSorter<>(staffTable.getModel());
        staffTable.setRowSorter(newRowSorter);
        
        // ... 原有逻辑 ...
    }
});

3. 优化代码,解决SQL注入与职责混乱

替换SQL拼接为PreparedStatement

在DatabaseConnector中新增安全的插入方法:

public void insertStaff(String name, String surname, String address, String postcode, String city, String login) throws SQLException {
    String sql = "INSERT INTO stafflist(`name`, `surname`, `address`, `postcode`, `city`,`login`) VALUES (?, ?, ?, ?, ?, ?)";
    try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
        pstmt.setString(1, name);
        pstmt.setString(2, surname);
        pstmt.setString(3, address);
        pstmt.setString(4, postcode);
        pstmt.setString(5, city);
        pstmt.setString(6, login);
        pstmt.executeUpdate();
    }
}

在StaffLibraryTable中调用该方法替代SQL拼接:

try {
    DatabaseConnector dbConnector = new DatabaseConnector();
    dbConnector.insertStaff(name, surname, address, postcode, city, login);
    JOptionPane.showMessageDialog(null, "Dodano pracownika");
    
    // 清空输入框与刷新表格逻辑...
} catch (SQLException ex) {
    JOptionPane.showMessageDialog(null, "添加失败:" + ex.getMessage());
    ex.printStackTrace();
}

拆分DatabaseConnector职责

将构造方法仅用于初始化连接,把增删改、查询等操作拆分为独立方法:

  • 新增executeUpdate(String sql, Object... params)处理增删改
  • 新增getTableModel(String sql)获取查询结果的TableModel
  • 新增refreshJTable(JTable table, String sql)专门负责刷新JTable

4. 修复loginChecker的SQL注入问题

static boolean loginChecker(String providedLogin) {
    boolean wynik = true;
    String sql = "SELECT * FROM loggintable WHERE login = ?";
    try (DatabaseConnector dbConnector = new DatabaseConnector();
         PreparedStatement pstmt = dbConnector.connection.prepareStatement(sql)) {
        pstmt.setString(1, providedLogin);
        try (ResultSet rs = pstmt.executeQuery()) {
            if (rs.next()) {
                wynik = false;
            }
        }
    } catch (SQLException e) {
        System.out.println("error in LoginChecker");
        System.out.println(e.getMessage());
    }
    return wynik;
}

内容的提问来源于stack exchange,提问作者Przemysław Poskrobko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:50:54