Ein Buch zurückgeben
Du bist Entwickler:in für das Verwaltungssystem der Metropolitan Public Library. Letzte Woche wurde ein kritischer Bug entdeckt: Wenn das System während der Rückgabe eines Buchs abstürzte, wurde das Darlehen als „zurückgegeben“ markiert, aber das Buch blieb im Bestand als „ausgeliehen“. Dadurch war das Buch wochenlang nicht verfügbar, bis Mitarbeitende die Datenbank manuell korrigierten.
Wenn ein Buch zurückgegeben wird, müssen drei Operationen gemeinsam erfolgreich sein oder gemeinsam scheitern:
- Den Ausleihdatensatz auf den Status „zurückgegeben“ setzen.
- Die Verfügbarkeit des Buchs von „ausgeliehen“ auf „verfügbar“ ändern.
- Eine Gebühr erfassen, wenn das Buch zu spät zurückgegeben wurde.
Deine Aufgabe ist es, eine korrekte Transaktionssteuerung zu implementieren, um die Datenkonsistenz sicherzustellen.
Diese Übung ist Teil des Kurses
Abfragen einer PostgreSQL-Datenbank in Java
Anleitung zur Übung
- Setze
autoCommitam Anfang in Zeile 26 auffalse. - Führe einen Commit durch, wenn alle Operationen erfolgreich sind, in Zeile 59.
- Falls eine Operation fehlschlägt, führe in Zeile 66 ein Rollback der Transaktion durch.
Interaktive Übung
Vervollständige den Beispielcode, um diese Übung erfolgreich abzuschließen.
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;
}
}
}