Transaction + Exception 처리

heeezni·2025년 6월 13일

Java GUI 프로젝트

목록 보기
16/20

트랜잭션 + 예외처리 전략

하나의 트랜잭션 안에서 여러 DML 작업이 수행되고,
그 중 하나라도 실패하면 전체를 롤백해야 한다.

ProductPage 중

insert() { // '등록'이라는 트랜잭션 시작
    product insert()              → 예외 전달
    product_color insert()        → 예외 전달
    product_size insert()         → 예외 전달
    product_img insert()          → 예외 전달
}
commit(); // 전부 성공 시 커밋

전략

  • 트랜잭션은 Connection 단위로 진행되기 때문에,
    모든 DML은 반드시 같은 커넥션으로 묶어서 처리하기!

  • 모든 DML은 하나의 Connection으로 묶기
    DBManager.getConnection() → DAO마다 동일한 커넥션 전달

  • 예외는 DAO 내부에서 catch하지 말고 throws로 바깥으로 던지기
    바깥쪽(서비스 또는 페이지)에서 한 번에 try-catch
    사용자에게는 이해할 수 있는 메시지만 보여주기


실제 코드

// MySQL에 상품 등록 관련 쿼리 수행
public void insert() {
	// 트랜잭션이 적용되려면, 4개의 DAO가 모두 같은 Connection을 사용해야 함
	Connection con = dbManager.getConnection();
	try {
		con.setAutoCommit(false); // start transaction 명령이 포함되어 있으므로 별도 호출 불필요

		// 이 영역은 트랜잭션의 "시도(try)" 영역
		// 이 중 하나라도 실패하면 catch 블록으로 이동 → rollback 수행
		// 모두 성공하면 commit 수행

		// Product 모델 인스턴스 생성 후, 상품 등록 데이터 세팅
		Product product = new Product();
		product.setSubcategory((SubCategory) cb_subcategory.getSelectedItem()); // FK (toString 오버라이딩 필요)
		product.setProduct_name(t_product_name.getText());
		product.setBrand(t_brand.getText());
		product.setPrice(Integer.parseInt(t_price.getText()));
		product.setDiscount(Integer.parseInt(t_discount.getText()));
		product.setIntroduce(t_introduce.getText());
		product.setDetail(t_detail.getText());

		// 상품 등록
		productDAO.insert(product);

		// 등록된 상품의 최신 PK 값을 가져와 product에 세팅
		int product_id = productDAO.selectRecentPk();
		product.setProduct_id(product_id); // ★ 최신 PK 값을 product에 반영

		// 상품에 연결된 색상 등록
		List<Color> colorList = t_color.getSelectedValuesList();
		for (Color color : colorList) {
			ProductColor productColor = new ProductColor();
			productColor.setProduct(product); // 어떤 상품에
			productColor.setColor(color);     // 어떤 색상을
			productColorDAO.insert(productColor);
		}

		// 상품에 연결된 사이즈 등록
		List<Size> sizeList = t_size.getSelectedValuesList();
		for (Size size : sizeList) {
			ProductSize productSize = new ProductSize();
			productSize.setProduct(product); // 어떤 상품에
			productSize.setSize(size);      // 어떤 사이즈를
			productSizeDAO.insert(productSize);
		}

		// 상품에 연결된 이미지 등록
		for (int i = 0; i < newFiles.length; i++) {
			File file = newFiles[i];
			ProductImg productImg = new ProductImg();
			productImg.setProduct(product);
			productImg.setFilename(file.getName());
			productImg.setProduct_img_id(productImg.getProduct().getProduct_id());
			productImgDAO.insert(productImg);
		}

		con.commit(); // 모든 작업이 정상 수행됨 → 트랜잭션 확정
	} catch (ProductException | ProductColorException | ProductSizeException | ProductImgException e) {
		// 상품 등록 관련 커스텀 예외들
		try {
			con.rollback(); // 트랜잭션 되돌리기
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		e.printStackTrace(); // 개발자를 위한 디버깅 출력
		JOptionPane.showMessageDialog(this, e.getMessage()); // 유저에게 메시지 전달
	} catch (SQLException e) {
		e.printStackTrace(); // JDBC 예외
	} finally {
		try {
			con.setAutoCommit(true); // 커넥션 상태 복원
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
profile
아이들의 가능성을 믿었던 마음 그대로, 이제는 나의 가능성을 믿고 나아가는 중입니다.🌱

0개의 댓글