시작하기무료로 시작하기

Book Club Saturdays

Metropolitan Public Library에서는 30~40명의 회원이 오전 10시에 모여 매월 선택한 도서를 대출하는 "Book Club Saturdays" 행사를 진행해요. 현재 시스템은 auto-commit이 활성화된 상태에서 각 대출을 개별적으로 처리하고 있어, 다음과 같은 두 가지 심각한 문제가 발생합니다:

  1. 데이터 불일치: 지난달에는 한 회원이 책 4권을 대출하는 중 시스템이 다운되었어요. 그중 2권만 대출로 기록되고 나머지 2권은 기록되지 않아, 재고가 맞지 않고 이용자 불만이 생겼습니다.
  2. 성능 병목: 각 대출을 별도의 데이터베이스 트랜잭션으로 처리하다 보니 15~20분이 소요되어 긴 대기열이 생기고 직원들의 업무 부담이 커집니다.

여러분의 과제는 트랜잭션 제어를 적용한 배치 처리를 구현하는 것입니다.

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

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

강의 보기

연습 안내

  • 32행에서 autoCommitfalse로 설정해 수동 트랜잭션 제어를 활성화하세요.
  • 43행에서 여러 건의 대출을 배치에 추가하세요.
  • 49행에서 모든 작업이 성공하면 트랜잭션을 커밋하세요.

실습형 인터랙티브 연습

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

public class BatchLoanProcessor {
    private static final String DB_URL = "jdbc:postgresql://localhost:5432/library_db";
    private static final String USERNAME = "postgres";
    private static final String PASSWORD = "postgres";
    
    public static void main(String[] args) {
        Object[][] loanData = {
            {1, 1, LocalDate.now(), LocalDate.now().plusDays(14), "borrowed"},
            {2, 2, LocalDate.now(), LocalDate.now().plusDays(14), "borrowed"},
            {3, 3, LocalDate.now(), LocalDate.now().plusDays(7), "borrowed"},
            {4, 1, LocalDate.now(), LocalDate.now().plusDays(14), "borrowed"}
        };
        
        try {
            boolean success = processBatchLoans(loanData);
            if (success) {
                System.out.println("All loans were processed successfully.");
            } else {
                System.out.println("Loan processing failed. Transaction was rolled back.");
            }
        } catch (SQLException e) {
            System.err.println("Database error: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    public static boolean processBatchLoans(Object[][] loanData) throws SQLException {
        String insertSQL = "INSERT INTO loans (book_id, member_id, loan_date, due_date, status) VALUES (?, ?, ?, ?, ?)";
        
        try (Connection conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD)) {
            // Set autoCommit to false
            conn.____(____);
            
            try (PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
                for (Object[] loan : loanData) {
                    pstmt.setInt(1, (Integer) loan[0]);  
                    pstmt.setInt(2, (Integer) loan[1]);  
                    pstmt.setDate(3, java.sql.Date.valueOf((LocalDate) loan[2]));  
                    pstmt.setDate(4, java.sql.Date.valueOf((LocalDate) loan[3]));  
                    pstmt.setString(5, (String) loan[4]);  
                    
                    // Add to batch
                    pstmt.____();
                }
                
                int[] results = pstmt.executeBatch();
                                
                // Commit the transaction if all operations are successful
                conn.____();
                
                return true;
            } catch (SQLException e) {
                conn.rollback();
                
                System.err.println("Error during batch processing: " + e.getMessage());
                return false;
            }
        }
    }
}
코드 편집 및 실행