Restituire un libro
Sei uno sviluppatore del sistema di gestione della Metropolitan Public Library. La settimana scorsa è stato scoperto un bug critico: quando il sistema andava in crash durante la restituzione di un libro, il prestito veniva segnato come "restituito" ma il libro restava "in prestito" nell'inventario. Questo rendeva il libro indisponibile per settimane, finché il personale non correggeva manualmente il database.
Quando un libro viene restituito, tre operazioni devono riuscire tutte insieme o fallire tutte insieme:
- Aggiornare il record del prestito allo stato "restituito".
- Cambiare la disponibilità del libro da "in prestito" a "disponibile".
- Registrare una multa se il libro viene restituito in ritardo.
Il tuo compito è implementare un corretto controllo delle transazioni per garantire la coerenza dei dati.
Questo esercizio fa parte del corso
Eseguire query su un database PostgreSQL in Java
Istruzioni dell'esercizio
- Imposta
autoCommitsufalseall'inizio alla riga 26. - Esegui il commit della transazione se tutte le operazioni vanno a buon fine alla riga 59.
- Se una qualsiasi operazione fallisce, esegui il rollback della transazione alla riga 66.
Esercizio pratico interattivo
Prova a risolvere questo esercizio completando il codice di esempio.
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;
}
}
}