Returnarea unei cărți
Ești un dezvoltator pentru sistemul de management al Bibliotecii Publice Metropolitane. Săptămâna trecută, a fost descoperit un bug critic: atunci când sistemul se bloca în timpul returnării unei cărți, împrumutul era marcat ca „returnat", însă cartea rămânea cu statusul „împrumutată" în inventar. Astfel, cartea devenea indisponibilă timp de câteva săptămâni, până când personalul corecta manual baza de date.
Atunci când o carte este returnată, trei operațiuni trebuie să reușească împreună sau să eșueze împreună:
- Actualizarea înregistrării împrumutului cu statusul „returnat".
- Schimbarea disponibilității cărții din „împrumutată" în „disponibilă".
- Înregistrarea unei amenzi dacă volumul este returnat cu întârziere.
Sarcina ta este să implementezi un control adecvat al tranzacțiilor pentru a asigura consistența datelor.
Acest exercițiu face parte din cursul
Interogarea unei baze de date PostgreSQL în Java
Instrucțiuni pentru exercițiu
- Setează
autoCommitlafalsela început, în linia 26. - Confirmă tranzacția dacă toate operațiunile reușesc, în linia 59.
- Dacă oricare dintre operațiuni eșuează, anulează tranzacția în linia 66.
Exercițiu interactiv practic
Încearcă acest exercițiu completând acest cod de exemplu.
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;
}
}
}