Mengembalikan buku
Anda adalah pengembang untuk sistem manajemen Metropolitan Public Library. Minggu lalu, ditemukan bug kritis: ketika sistem crash saat pengembalian buku, pinjaman ditandai sebagai "returned" tetapi buku tetap berstatus "checked-out" di inventaris. Akibatnya, buku tidak tersedia selama berminggu-minggu hingga staf memperbaiki basis data secara manual.
Saat buku dikembalikan, tiga operasi berikut harus berhasil bersama-sama atau gagal bersama-sama:
- Memperbarui catatan pinjaman ke status "returned".
- Mengubah ketersediaan buku dari "checked-out" menjadi "available".
- Mencatat denda jika buku dikembalikan terlambat.
Tugas Anda adalah menerapkan kontrol transaksi yang tepat untuk memastikan konsistensi data.
Latihan ini adalah bagian dari kursus
Melakukan Query ke Basis Data PostgreSQL di Java
Petunjuk latihan
- Setel
autoCommitmenjadifalsedi awal pada baris 26. - Commit transaksi jika semua operasi berhasil pada baris 59.
- Jika ada operasi yang gagal, lakukan rollback transaksi pada baris 66.
Latihan interaktif praktis
Cobalah latihan ini dengan menyelesaikan kode contoh berikut.
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;
}
}
}