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

NetBeans 8中Java DB报错:当前光标位置操作无效(图书归还功能)

问题描述

我在NetBeans 8中开发图书馆图书归还按钮功能:图书逾期归还时向借阅者收取费用,在规定日期内归还则不收费,但运行时出现报错:Invalid operation at current cursor position.

相关实现代码:

private void btnReturnActionPerformed(java.awt.event.ActionEvent evt) {                                         
    String rCustomer = customerName.getText();
    String rDate = Date.getText();
    String rBook = bookName.getText();
    String rStatus = "Available";
    

    if (rCustomer.equals("") || rDate.equals("")
        || rBook.equals("")) {
        JOptionPane.showMessageDialog(this, "Please Enter Required Details");
    } else {
        try {
            String returnDateString = Rset2.getString("RETURNDATE");
            Date returnDate = new SimpleDateFormat("yyyy-MM-dd").parse(returnDateString);
            Date currentDate = new Date();
            long balance = ( currentDate.getTime() - returnDate.getTime() )/ (24 * 60 * 60 * 1000);
            if (balance < 0){
                String updateSQL = "UPDATE ADMIN1.INVENTORY SET STATUS = '" + rStatus + "', DATE = NULL WHERE BOOKNAME = '" + rBook + "'";
                state.executeUpdate(updateSQL);
               
                JOptionPane.showMessageDialog(this, "Book Returned Successfully");
                LibraryFrame lib = new LibraryFrame();
                lib.setVisible(true);
                dispose();
            }else {
            
            int choice = JOptionPane.showConfirmDialog(this, "Please pay the fee of: " + balance, "Alert", JOptionPane.OK_CANCEL_OPTION);

            if (choice == JOptionPane.OK_OPTION) {
                try {
                    String deleteSQL = "DELETE FROM ADMIN1.BORROWEDBOOK WHERE CustomerName = '" + rCustomer + "' AND BookName = '"+ rBook + "'";
                    Rset2 = state.executeQuery(deleteSQL);
                    JOptionPane.showMessageDialog(this, "Payment Successfull");
                } catch( SQLException err ){
                    System.out.println(err.getMessage());
                }
            }
            }
            conn.commit();
            Rset.close();
            Rset2.close();
            state.close();

            JOptionPane.showMessageDialog(this, "Book Borrowed Successfully");
            LibraryFrame lib = new LibraryFrame();
            lib.setVisible(true);
            dispose();

        } catch (SQLException err) {
            System.out.println(err.getMessage());
        }   catch (ParseException ex) {
                Logger.getLogger(returnBook.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

错误原因及修复方案

1. ResultSet游标未定位

报错核心原因是直接调用Rset2.getString("RETURNDATE")时,ResultSet游标未指向有效数据行。ResultSet默认初始位置在第一行之前,必须先调用next()方法移动游标到有效行才能读取数据。

修改代码:

// 原代码:String returnDateString = Rset2.getString("RETURNDATE");
if (Rset2.next()) {
    String returnDateString = Rset2.getString("RETURNDATE");
    // 后续日期解析、计算逻辑
} else {
    JOptionPane.showMessageDialog(this, "未找到该图书的借阅记录");
    return; // 终止后续逻辑
}

2. DELETE语句执行方法错误

执行DELETE、UPDATE这类更新数据库的语句,必须使用executeUpdate()方法,而非executeQuery()(后者仅用于查询并返回ResultSet)。用executeQuery()执行DELETE会返回空ResultSet,后续操作会触发游标位置错误。

同时,原代码字符串拼接SQL存在SQL注入风险,建议改用PreparedStatement:

// 原逾期处理中的DELETE代码替换为:
if (choice == JOptionPane.OK_OPTION) {
    try {
        String deleteSQL = "DELETE FROM ADMIN1.BORROWEDBOOK WHERE CustomerName = ? AND BookName = ?";
        PreparedStatement pstmt = conn.prepareStatement(deleteSQL);
        pstmt.setString(1, rCustomer);
        pstmt.setString(2, rBook);
        int rowsDeleted = pstmt.executeUpdate();
        if (rowsDeleted > 0) {
            JOptionPane.showMessageDialog(this, "缴费成功");
            // 同步更新库存状态
            String updateSQL = "UPDATE ADMIN1.INVENTORY SET STATUS = ?, DATE = NULL WHERE BOOKNAME = ?";
            PreparedStatement updatePstmt = conn.prepareStatement(updateSQL);
            updatePstmt.setString(1, rStatus);
            updatePstmt.setString(2, rBook);
            updatePstmt.executeUpdate();
            updatePstmt.close();
        } else {
            JOptionPane.showMessageDialog(this, "未找到对应借阅记录");
        }
        pstmt.close();
    } catch( SQLException err ){
        System.out.println(err.getMessage());
    }
}

3. 代码逻辑混乱修复

  • 原代码中按时归还分支已执行dispose()关闭窗口,后续的事务提交、资源关闭和重复页面跳转代码不会执行,且存在资源泄漏风险。建议用try-with-resources自动关闭数据库资源,或把资源关闭逻辑放在finally块中。
  • 最后错误的提示文本Book Borrowed Successfully改为图书归还完成,避免语义错误。
  • 移除重复的页面跳转代码,确保逻辑流程清晰。

4. 其他细节优化

  • 变量名Date是Java自带类名,作为文本框变量名易混淆,建议改为returnDateTxt这类有意义的名字。
  • 日期计算时,当前时间包含时分秒可能导致逾期天数计算偏差,建议转为纯日期比较:
// 替换原日期计算逻辑:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getDefault()); // 设置时区避免偏差
Date returnDate = sdf.parse(returnDateString);
Date currentDate = sdf.parse(sdf.format(new Date())); // 忽略时分秒,仅保留日期部分
long overdueDays = (currentDate.getTime() - returnDate.getTime()) / (24 * 60 * 60 * 1000);

修复后完整代码示例

private void btnReturnActionPerformed(java.awt.event.ActionEvent evt) {                                         
    String rCustomer = customerName.getText();
    String rDate = returnDateTxt.getText(); // 重命名Date文本框为returnDateTxt
    String rBook = bookName.getText();
    String rStatus = "Available";
    
    if (rCustomer.trim().isEmpty() || rDate.trim().isEmpty() || rBook.trim().isEmpty()) {
        JOptionPane.showMessageDialog(this, "请填写必要信息");
        return;
    }

    try (Statement state = conn.createStatement()) { // try-with-resources自动关闭资源
        // 先查询借阅记录的归还日期
        String querySQL = "SELECT RETURNDATE FROM ADMIN1.BORROWEDBOOK WHERE CustomerName = ? AND BookName = ?";
        try (PreparedStatement queryPstmt = conn.prepareStatement(querySQL)) {
            queryPstmt.setString(1, rCustomer);
            queryPstmt.setString(2, rBook);
            try (ResultSet Rset2 = queryPstmt.executeQuery()) {
                if (!Rset2.next()) {
                    JOptionPane.showMessageDialog(this, "未找到该图书的借阅记录");
                    return;
                }

                String returnDateString = Rset2.getString("RETURNDATE");
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                sdf.setTimeZone(TimeZone.getDefault());
                Date returnDate = sdf.parse(returnDateString);
                Date currentDate = sdf.parse(sdf.format(new Date()));
                long overdueDays = (currentDate.getTime() - returnDate.getTime()) / (24 * 60 * 60 * 1000);

                if (overdueDays < 0) {
                    // 按时归还,更新库存并删除借阅记录
                    String updateSQL = "UPDATE ADMIN1.INVENTORY SET STATUS = ?, DATE = NULL WHERE BOOKNAME = ?";
                    try (PreparedStatement updatePstmt = conn.prepareStatement(updateSQL)) {
                        updatePstmt.setString(1, rStatus);
                        updatePstmt.setString(2, rBook);
                        updatePstmt.executeUpdate();
                    }
                    String deleteSQL = "DELETE FROM ADMIN1.BORROWEDBOOK WHERE CustomerName = ? AND BookName = ?";
                    try (PreparedStatement deletePstmt = conn.prepareStatement(deleteSQL)) {
                        deletePstmt.setString(1, rCustomer);
                        deletePstmt.setString(2, rBook);
                        deletePstmt.executeUpdate();
                    }
                    JOptionPane.showMessageDialog(this, "图书归还成功");
                } else {
                    // 逾期,提示缴费
                    int choice = JOptionPane.showConfirmDialog(this, "请支付逾期费用:" + overdueDays + "元", "提示", JOptionPane.OK_CANCEL_OPTION);
                    if (choice == JOptionPane.OK_OPTION) {
                        // 删除借阅记录并更新库存
                        String deleteSQL = "DELETE FROM ADMIN1.BORROWEDBOOK WHERE CustomerName = ? AND BookName = ?";
                        try (PreparedStatement deletePstmt = conn.prepareStatement(deleteSQL)) {
                            deletePstmt.setString(1, rCustomer);
                            deletePstmt.setString(2, rBook);
                            int rowsDeleted = deletePstmt.executeUpdate();
                            if (rowsDeleted > 0) {
                                String updateSQL = "UPDATE ADMIN1.INVENTORY SET STATUS = ?, DATE = NULL WHERE BOOKNAME = ?";
                                try (PreparedStatement updatePstmt = conn.prepareStatement(updateSQL)) {
                                    updatePstmt.setString(1, rStatus);
                                    updatePstmt.setString(2, rBook);
                                    updatePstmt.executeUpdate();
                                }
                                JOptionPane.showMessageDialog(this, "缴费成功,图书已归还");
                            } else {
                                JOptionPane.showMessageDialog(this, "未找到对应借阅记录");
                                return;
                            }
                        }
                    } else {
                        JOptionPane.showMessageDialog(this, "已取消归还操作");
                        return;
                    }
                }
            }
        }
        conn.commit();
        JOptionPane.showMessageDialog(this, "图书归还完成");
        LibraryFrame lib = new LibraryFrame();
        lib.setVisible(true);
        dispose();
    } catch (SQLException err) {
        System.out.println(err.getMessage());
        try {
            conn.rollback(); // 出错回滚事务
        } catch (SQLException e) {
            e.printStackTrace();
        }
    } catch (ParseException ex) {
        Logger.getLogger(returnBook.class.getName()).log(Level.SEVERE, null, ex);
        JOptionPane.showMessageDialog(this, "日期格式错误,请检查输入");
    }
}

内容的提问来源于stack exchange,提问作者Ley Cabs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 12:57:05