Retour d’un livre
Vous êtes développeur du système de gestion de la Metropolitan Public Library. La semaine dernière, un bogue critique a été découvert : lorsque le système plantait pendant un retour de livre, l’emprunt passait à l’état « returned », mais le livre restait « checked-out » dans l’inventaire. Le livre devenait alors indisponible pendant des semaines, jusqu’à ce que le personnel corrige la base de données manuellement.
Lorsqu’un livre est rendu, trois opérations doivent réussir ou échouer ensemble :
- Mettre à jour l’enregistrement d’emprunt avec le statut « returned ».
- Passer la disponibilité du livre de « checked-out » à « available ».
- Enregistrer une amende si le livre est rendu en retard.
Votre mission est de mettre en place un contrôle de transaction approprié pour garantir la cohérence des données.
Cet exercice fait partie du cours
Interroger une base de données PostgreSQL en Java
Instructions
- Définissez
autoCommitsurfalseau début à la ligne 26. - Validez la transaction si toutes les opérations réussissent à la ligne 59.
- Si une opération échoue, annulez la transaction à la ligne 66.
Exercice interactif pratique
Essayez cet exercice en complétant cet exemple de code.
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;
}
}
}