시작하기무료로 시작하기

도서 반납 처리

당신은 Metropolitan Public Library의 관리 시스템을 담당하는 개발자입니다. 지난주에 치명적인 버그가 발견되었는데, 시스템이 도서 반납 중에 장애가 발생하면 대출 기록은 "returned"로 표시되지만, 재고에서는 해당 도서가 여전히 "checked-out" 상태로 남는 문제였습니다. 이로 인해 직원이 수동으로 데이터베이스를 수정할 때까지 수주 동안 도서를 이용할 수 없었습니다.

도서가 반납될 때는 다음 세 가지 작업이 함께 성공하거나 함께 실패해야 합니다.

  1. 대출 기록을 "returned" 상태로 업데이트합니다.
  2. 도서의 이용 가능 상태를 "checked-out"에서 "available"로 변경합니다.
  3. 반납이 늦은 경우 연체료를 기록합니다.

데이터 일관성을 보장하도록 올바른 트랜잭션 제어를 구현하세요.

이 연습은 강의의 일부입니다

Java에서 PostgreSQL 데이터베이스 질의하기

강의 보기

연습 안내

  • 26번째 줄에서 autoCommitfalse로 설정하세요.
  • 모든 작업이 성공하면 59번째 줄에서 트랜잭션을 커밋하세요.
  • 어떤 작업이든 실패하면 66번째 줄에서 트랜잭션을 롤백하세요.

실습형 인터랙티브 연습

이 예제를 이 샘플 코드를 완성하여 풀어보세요.

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;
        }
    }
}
코드 편집 및 실행