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