เริ่มต้นใช้งานเริ่มต้นใช้งานได้ฟรี

การคืนหนังสือ

คุณเป็นนักพัฒนาระบบจัดการของห้องสมุดสาธารณะ Metropolitan สัปดาห์ที่ผ่านมามีการค้นพบบั๊กสำคัญ: เมื่อระบบเกิดขัดข้องระหว่างการคืนหนังสือ บันทึกการยืมถูกทำเครื่องหมายว่า "คืนแล้ว" แต่หนังสือยังคงแสดงสถานะ "ถูกยืมออก" ในคลังข้อมูล ส่งผลให้หนังสือไม่สามารถให้ยืมได้นานหลายสัปดาห์ จนกว่าเจ้าหน้าที่จะแก้ไขฐานข้อมูลด้วยตนเอง

เมื่อมีการคืนหนังสือ การดำเนินการสามขั้นตอนต่อไปนี้ต้องสำเร็จพร้อมกันหรือล้มเหลวพร้อมกันทั้งหมด:

  1. อัปเดตบันทึกการยืมให้เป็นสถานะ "คืนแล้ว"
  2. เปลี่ยนสถานะความพร้อมใช้งานของหนังสือจาก "ถูกยืมออก" เป็น "พร้อมให้ยืม"
  3. บันทึกค่าปรับหากคืนหนังสือล่าช้า

ให้ใช้การควบคุม transaction ที่เหมาะสมเพื่อให้มั่นใจว่าข้อมูลมีความสอดคล้องกัน

แบบฝึกหัดนี้เป็นส่วนหนึ่งของหลักสูตร

การคิวรีฐานข้อมูล PostgreSQL ด้วย Java

ดูคอร์ส

คำแนะนำการฝึกหัด

  • ตั้งค่า autoCommit เป็น false ที่จุดเริ่มต้นใน บรรทัดที่ 26
  • commit transaction หากการดำเนินการทั้งหมดสำเร็จใน บรรทัดที่ 59
  • หากการดำเนินการใดล้มเหลว ให้ roll back transaction ใน บรรทัดที่ 66

แบบฝึกหัดเชิงโต้ตอบแบบลงมือทำ

ลองทำแบบฝึกหัดนี้โดยเติมโค้ดตัวอย่างนี้ให้สมบูรณ์

public class BookReturnProcessor {
    public static void main(String[] args) {
        int loanId = 1;
        int bookId = 5;
        LocalDate dueDate = LocalDate.now().minusDays(2);
        
        try {
            boolean success = processBookReturn(loanId, bookId, dueDate);
            if (success) {
                System.out.println("Book return processed successfully.");
            } else {
                System.out.println("Book return processing failed.");
            }
        } catch (SQLException e) {
            System.err.println("Database error: " + e.getMessage());
        }
    }
    
    public static boolean processBookReturn(int loanId, int bookId, LocalDate dueDate) throws SQLException {
        Connection conn = null;
        try {
            HikariDataSource ds = HikariSetup.createDataSource();
            conn = ds.getConnection();
            
            // Start transaction by setting autoCommit to false
            conn.____(____);
            
            String updateLoanSQL = "UPDATE loans SET status = 'returned', return_date = ? WHERE loan_id = ?";
            try (PreparedStatement pstmt = conn.prepareStatement(updateLoanSQL)) {
                pstmt.setDate(1, java.sql.Date.valueOf(LocalDate.now()));
                pstmt.setInt(2, loanId);
                pstmt.executeUpdate();
            }
            
            String updateBookSQL = "UPDATE books SET status = 'available' WHERE book_id = ?";
            try (PreparedStatement pstmt = conn.prepareStatement(updateBookSQL)) {
                pstmt.setInt(1, bookId);
                pstmt.executeUpdate();
            }
            
            LocalDate today = LocalDate.now();
            if (today.isAfter(dueDate)) {
                long daysLate = ChronoUnit.DAYS.between(dueDate, today);
                double fineAmount = daysLate * 0.50;
                
                String insertFineSQL = "INSERT INTO fines (loan_id, amount, reason, date_assessed) VALUES (?, ?, ?, ?)";
                try (PreparedStatement pstmt = conn.prepareStatement(insertFineSQL)) {
                    pstmt.setInt(1, loanId);
                    pstmt.setDouble(2, fineAmount);
                    pstmt.setString(3, "Book returned " + daysLate + " days late");
                    pstmt.setDate(4, java.sql.Date.valueOf(today));
                    pstmt.executeUpdate();
                }
                
                System.out.println("Fine created: $" + fineAmount + " for loan " + loanId);
            }
            
            // Commit the transaction
            conn.____();
            
            return true;
            
        } catch (SQLException e) {
            // Roll back the transaction if an error occurs
            if (conn != null) {
                conn.____();
            }
            System.err.println("Error processing return: " + e.getMessage());
            return false;
        }
    }
}
แก้ไขและรันโค้ด