개인 개발 공부 일지

JDBC, 트랜잭션

everydeveloper 2024. 6. 24. 18:01

JDBC에 대해 설명하시오 (키워드: 드라이버, 트랜잭션, 커넥션 풀)

JDBC(Java Database Connectivity)는 자바 애플리케이션이 데이터베이스와 상호작용할 수 있도록 하는 API입니다. JDBC를 사용하면 데이터베이스에 연결하고, SQL 쿼리를 실행하며, 결과를 처리할 수 있습니다. JDBC의 주요 구성 요소와 관련된 개념들을 설명하겠습니다.

1. JDBC 드라이버

JDBC 드라이버는 자바 애플리케이션과 데이터베이스 간의 통신을 가능하게 하는 소프트웨어 컴포넌트입니다. JDBC 드라이버는 네 가지 유형으로 분류됩니다:

  1. Type 1: JDBC-ODBC Bridge Driver
    • ODBC 드라이버를 사용하여 데이터베이스에 연결합니다.
    • 개발 및 테스트 목적으로 주로 사용되며, 배포용으로는 적합하지 않습니다.
  2. Type 2: Native-API Driver
    • 데이터베이스의 네이티브 API를 사용하여 JDBC 호출을 변환합니다.
    • 데이터베이스 클라이언트 라이브러리가 필요합니다.
  3. Type 3: Network Protocol Driver
    • 미들웨어 서버를 통해 데이터베이스와 통신합니다.
    • 다양한 데이터베이스에 대한 연결을 지원합니다.
  4. Type 4: Thin Driver
    • 순수 자바로 작성된 드라이버로, 네이티브 라이브러리가 필요 없습니다.
    • 데이터베이스와 직접 통신합니다.

Type 4 드라이버가 가장 많이 사용되며, 성능과 호환성 면에서 우수합니다[3][4].

2. 트랜잭션

트랜잭션은 데이터베이스 작업의 논리적 단위로, 일련의 SQL 명령어들을 하나의 작업으로 묶어 처리합니다. 트랜잭션은 원자성, 일관성, 고립성, 지속성(ACID) 특성을 보장합니다.

트랜잭션 관리

JDBC에서 트랜잭션을 관리하려면 Connection 객체의 setAutoCommit(false) 메서드를 사용하여 자동 커밋 모드를 비활성화해야 합니다. 그런 다음, 필요한 SQL 명령어를 실행하고, commit() 메서드를 호출하여 트랜잭션을 커밋하거나, rollback() 메서드를 호출하여 롤백할 수 있습니다.

Connection connection = dataSource.getConnection();
try {
    connection.setAutoCommit(false); // 트랜잭션 시작
    // SQL 명령어 실행
    connection.commit(); // 트랜잭션 커밋
} catch (SQLException e) {
    connection.rollback(); // 트랜잭션 롤백
} finally {
    connection.setAutoCommit(true); // 자동 커밋 모드 복원
}

트랜잭션을 사용하면 데이터 일관성을 유지하고, 여러 SQL 명령어가 모두 성공적으로 실행되거나 모두 실패하도록 보장할 수 있습니다[1][7][8].

3. 커넥션 풀

커넥션 풀은 데이터베이스 연결을 효율적으로 관리하기 위한 메커니즘입니다. 커넥션 풀은 미리 일정 수의 Connection 객체를 생성해 두고, 필요할 때마다 이를 재사용합니다. 이를 통해 데이터베이스 연결을 생성하고 닫는 데 드는 오버헤드를 줄일 수 있습니다.

커넥션 풀의 동작 방식

  1. 애플리케이션 시작 시점에 커넥션 풀은 미리 설정된 수의 Connection 객체를 생성합니다.
  2. 클라이언트 요청이 들어오면 커넥션 풀에서 사용 가능한 Connection 객체를 빌려줍니다.
  3. 클라이언트가 작업을 마치면 Connection 객체를 커넥션 풀에 반환합니다.
  4. 커넥션 풀은 반환된 Connection 객체를 재사용할 수 있도록 준비합니다.

예제: HikariCP 설정

HikariCP는 성능이 뛰어난 JDBC 커넥션 풀 라이브러리입니다. Spring Boot에서 HikariCP를 설정하는 예제는 다음과 같습니다:

# application.yml
spring:
  datasource:
    hikari:
      pool-name: myPool
      jdbc-url: jdbc:mysql://localhost:3306/mydb
      username: myuser
      password: mypassword
      maximum-pool-size: 10
      minimum-idle: 5
      connection-timeout: 30000

커넥션 풀을 사용하면 데이터베이스 연결의 생성 및 종료에 따른 오버헤드를 줄이고, 애플리케이션의 성능을 향상시킬 수 있습니다[2][5][6].

이와 같이 JDBC 드라이버, 트랜잭션, 커넥션 풀은 자바 애플리케이션에서 데이터베이스와의 효율적이고 안전한 상호작용을 가능하게 하는 중요한 요소들입니다.

Citations: [1] https://jeong-pro.tistory.com/228 [2] https://technet.tmaxsoft.com/upload/download/online/jeus/pver-20150722-000001/server/chapter_datasource.html [3] https://www.geeksforgeeks.org/jdbc-drivers/ [4] https://learn.microsoft.com/ko-kr/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server?view=sql-server-ver16 [5] https://shuu.tistory.com/130 [6] https://steady-coding.tistory.com/564 [7] https://www.tutorialspoint.com/jdbc/jdbc-transactions.htm [8] https://stackoverflow.com/questions/4940648/how-to-start-a-transaction-in-jdbc [9] https://www.oracle.com/kr/database/technologies/appdev/jdbc-downloads.html [10] https://hudi.blog/java-db-connection-pooling/ [11] https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html [12] https://codevang.tistory.com/206 [13] https://www.oracle.com/kr/database/technologies/appdev/jdbc.html [14] https://pjh3749.tistory.com/87 [15] https://blog.naver.com/pjm5111/220719619162?viewType=pc

spring의 @Transactional 애노테이션은 어떻게 작동하나요

Spring의 @Transactional 애노테이션은 트랜잭션 관리를 간편하게 해주는 선언적 트랜잭션 관리 방식입니다. 이 애노테이션을 사용하면 트랜잭션의 시작, 커밋, 롤백을 자동으로 처리할 수 있습니다. @Transactional 애노테이션의 작동 방식과 주요 특징을 설명하겠습니다.

작동 방식

  1. 애노테이션 적용:
    • @Transactional 애노테이션은 클래스나 메소드에 적용할 수 있습니다. 클래스에 적용하면 해당 클래스의 모든 메소드에 트랜잭션이 적용되고, 메소드에 적용하면 해당 메소드에만 트랜잭션이 적용됩니다.
    • 예제:
    • @Transactional public class MyService { public void performOperation() { // 트랜잭션 내에서 실행됨 } }
  2. 프록시 생성:
    • Spring은 @Transactional이 적용된 클래스나 메소드에 대해 프록시 객체를 생성합니다. 이 프록시 객체는 메소드 호출을 가로채서 트랜잭션을 시작하고, 메소드 실행 후 트랜잭션을 커밋하거나 롤백합니다1.
  3. 트랜잭션 시작:
    • 프록시 객체는 @Transactional이 적용된 메소드가 호출될 때 트랜잭션을 시작합니다. 트랜잭션이 시작되면 데이터베이스 연결이 설정되고, 필요한 경우 잠금이 설정됩니다.
  4. 트랜잭션 커밋 및 롤백:
    • 메소드가 정상적으로 완료되면 트랜잭션이 커밋됩니다. 메소드 실행 중 예외가 발생하면 트랜잭션이 롤백됩니다. 기본적으로 RuntimeException이나 Error가 발생하면 롤백되며, CheckedException은 롤백되지 않습니다. 필요에 따라 rollbackFor 속성을 사용하여 롤백 조건을 지정할 수 있습니다4.
    • @Transactional(rollbackFor = Exception.class) public void performOperation() throws Exception { // 예외 발생 시 롤백 }
  5. 트랜잭션 관리 설정:
    • @EnableTransactionManagement 애노테이션을 사용하여 트랜잭션 관리 기능을 활성화해야 합니다. 이 애노테이션은 Spring의 트랜잭션 관리 인프라를 설정합니다2.
    • @Configuration @EnableTransactionManagement public class AppConfig { // 트랜잭션 관리 설정 }

주요 특징

  1. 선언적 트랜잭션 관리:
    • 코드 내에서 명시적으로 트랜잭션을 시작하고 종료하는 대신, 애노테이션을 사용하여 트랜잭션을 선언적으로 관리할 수 있습니다.
  2. 프록시 기반:
    • 기본적으로 Spring은 프록시를 사용하여 트랜잭션을 관리합니다. 프록시는 외부에서 메소드 호출을 가로채서 트랜잭션을 처리합니다. 내부 메소드 호출(self-invocation)은 트랜잭션이 적용되지 않습니다1.
  3. AspectJ 지원:
    • 프록시 기반 트랜잭션 관리 외에도 AspectJ를 사용하여 트랜잭션을 관리할 수 있습니다. AspectJ를 사용하면 내부 메소드 호출에도 트랜잭션이 적용됩니다1.
  4. 트랜잭션 전파:
    • @Transactional 애노테이션은 트랜잭션 전파(propagation) 속성을 지원합니다. 이를 통해 트랜잭션이 이미 존재하는 경우 새로운 트랜잭션을 시작할지, 기존 트랜잭션에 참여할지 등을 설정할 수 있습니다.
    • @Transactional(propagation = Propagation.REQUIRED) public void performOperation() { // 트랜잭션 전파 설정 }
  5. 트랜잭션 격리 수준:
    • 트랜잭션 격리 수준을 설정하여 트랜잭션 간의 데이터 일관성을 제어할 수 있습니다.
    • @Transactional(isolation = Isolation.SERIALIZABLE) public void performOperation() { // 트랜잭션 격리 수준 설정 }

이와 같이 @Transactional 애노테이션을 사용하면 트랜잭션 관리를 간편하게 할 수 있으며, 데이터베이스의 일관성과 무결성을 유지할 수 있습니다.

Citations: 1 https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/annotations.html[2](https://www.geeksforgeeks.org/spring-boot-transaction-management-using-transactional-annotation/) https://www.geeksforgeeks.org/spring-boot-transaction-management-using-transactional-annotation/[3](https://imiyoungman.tistory.com/9) https://imiyoungman.tistory.com/9[4](https://velog.io/%40kdhyo/JavaTransactional-Annotation-알고-쓰자-26her30h) https://velog.io/%40kdhyo/JavaTransactional-Annotation-알고-쓰자-26her30h [5] https://blog.naver.com/seek316/222707671228

@Transactional 애노테이션을 클래스 수준과 메서드 수준에서 각각 어떻게 사용하나요

Spring의 @Transactional 애노테이션은 클래스 수준과 메서드 수준에서 각각 다르게 작동할 수 있습니다. 이를 통해 트랜잭션 관리를 보다 유연하게 설정할 수 있습니다. 각 수준에서의 사용 방법과 작동 방식을 설명하겠습니다.

클래스 수준에서의 @Transactional

클래스 수준에서 @Transactional 애노테이션을 사용하면 해당 클래스의 모든 메서드에 트랜잭션이 적용됩니다. 이는 클래스 내의 모든 메서드가 동일한 트랜잭션 설정을 공유하게 됩니다.

예제

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class UserServiceImpl implements UserService {

    @Override
    public void createUser(User user) {
        // 트랜잭션 내에서 실행됨
    }

    @Override
    public User getUser(Long id) {
        // 트랜잭션 내에서 실행됨
        return userRepository.findById(id).orElse(null);
    }
}

작동 방식

  • 클래스 수준에서 @Transactional을 선언하면, 해당 클래스의 모든 public 메서드에 트랜잭션이 적용됩니다.
  • 트랜잭션 설정을 일관되게 적용할 수 있어 코드가 간결해집니다.
  • 클래스 수준의 설정은 메서드 수준의 설정에 의해 재정의될 수 있습니다.

메서드 수준에서의 @Transactional

메서드 수준에서 @Transactional 애노테이션을 사용하면 특정 메서드에만 트랜잭션이 적용됩니다. 이는 메서드별로 다른 트랜잭션 설정을 적용할 수 있게 합니다.

예제

import org.springframework.transaction.annotation.Transactional;

public class UserServiceImpl implements UserService {

    @Override
    @Transactional
    public void createUser(User user) {
        // 트랜잭션 내에서 실행됨
    }

    @Override
    public User getUser(Long id) {
        // 트랜잭션 없이 실행됨
        return userRepository.findById(id).orElse(null);
    }
}

작동 방식

  • 메서드 수준에서 @Transactional을 선언하면, 해당 메서드에만 트랜잭션이 적용됩니다.
  • 메서드별로 다른 트랜잭션 설정을 적용할 수 있어 유연성이 높아집니다.
  • 클래스 수준의 설정이 있는 경우, 메서드 수준의 설정이 우선합니다.

클래스 수준과 메서드 수준의 차이점

  1. 적용 범위:
    • 클래스 수준: 클래스 내 모든 public 메서드에 트랜잭션이 적용됩니다.
    • 메서드 수준: 특정 메서드에만 트랜잭션이 적용됩니다.
  2. 유연성:
    • 클래스 수준: 일관된 트랜잭션 설정을 적용할 수 있어 코드가 간결해집니다.
    • 메서드 수준: 메서드별로 다른 트랜잭션 설정을 적용할 수 있어 유연성이 높아집니다.
  3. 재정의:
    • 클래스 수준의 설정은 메서드 수준의 설정에 의해 재정의될 수 있습니다. 즉, 클래스 수준에서 @Transactional을 선언하고, 특정 메서드에서 다른 트랜잭션 설정을 적용할 수 있습니다.

예제: 클래스 수준과 메서드 수준의 혼합 사용

import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly = true)
public class UserServiceImpl implements UserService {

    @Override
    public User getUser(Long id) {
        // 읽기 전용 트랜잭션 내에서 실행됨
        return userRepository.findById(id).orElse(null);
    }

    @Override
    @Transactional
    public void createUser(User user) {
        // 읽기 전용이 아닌 트랜잭션 내에서 실행됨
        userRepository.save(user);
    }
}

이 예제에서는 클래스 수준에서 @Transactional(readOnly = true)를 선언하여 기본적으로 모든 메서드가 읽기 전용 트랜잭션 내에서 실행되도록 설정하고, createUser 메서드에서는 읽기 전용이 아닌 트랜잭션을 적용하여 데이터를 수정할 수 있도록 설정했습니다.

이와 같이 @Transactional 애노테이션을 클래스 수준과 메서드 수준에서 적절히 사용하면 트랜잭션 관리를 유연하고 효율적으로 할 수 있습니다.

Citations: [1] https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/annotations.html [2] https://stackoverflow.com/questions/23132822/what-is-the-difference-between-defining-transactional-on-class-vs-method [3] https://imiyoungman.tistory.com/9 [4] https://velog.io/%40kdhyo/JavaTransactional-Annotation-알고-쓰자-26her30h [5] https://blog.naver.com/seek316/222707671228

@Transactional 애노테이션을 사용하여 비즈니스 로직을 분리하는 방법은 무엇인가요

Spring의 @Transactional 애노테이션을 사용하여 비즈니스 로직을 분리하는 방법은 트랜잭션 관리를 선언적으로 처리하여 코드의 가독성과 유지보수성을 높이는 것입니다. 이를 통해 데이터베이스 작업의 일관성과 무결성을 보장할 수 있습니다. @Transactional 애노테이션을 클래스 수준과 메서드 수준에서 각각 사용하는 방법을 설명하겠습니다.

클래스 수준에서 @Transactional 사용

클래스 수준에서 @Transactional 애노테이션을 사용하면 해당 클래스의 모든 public 메서드에 트랜잭션이 적용됩니다. 이는 클래스 내의 모든 메서드가 동일한 트랜잭션 설정을 공유하게 됩니다.

예제

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class UserServiceImpl implements UserService {

    @Override
    public void createUser(User user) {
        // 트랜잭션 내에서 실행됨
        userRepository.save(user);
    }

    @Override
    public User getUser(Long id) {
        // 트랜잭션 내에서 실행됨
        return userRepository.findById(id).orElse(null);
    }
}

작동 방식

  • 클래스 수준에서 @Transactional을 선언하면, 해당 클래스의 모든 public 메서드에 트랜잭션이 적용됩니다.
  • 트랜잭션 설정을 일관되게 적용할 수 있어 코드가 간결해집니다.
  • 클래스 수준의 설정은 메서드 수준의 설정에 의해 재정의될 수 있습니다.

메서드 수준에서 @Transactional 사용

메서드 수준에서 @Transactional 애노테이션을 사용하면 특정 메서드에만 트랜잭션이 적용됩니다. 이는 메서드별로 다른 트랜잭션 설정을 적용할 수 있게 합니다.

예제

import org.springframework.transaction.annotation.Transactional;

public class UserServiceImpl implements UserService {

    @Override
    @Transactional
    public void createUser(User user) {
        // 트랜잭션 내에서 실행됨
        userRepository.save(user);
    }

    @Override
    public User getUser(Long id) {
        // 트랜잭션 없이 실행됨
        return userRepository.findById(id).orElse(null);
    }
}

작동 방식

  • 메서드 수준에서 @Transactional을 선언하면, 해당 메서드에만 트랜잭션이 적용됩니다.
  • 메서드별로 다른 트랜잭션 설정을 적용할 수 있어 유연성이 높아집니다.
  • 클래스 수준의 설정이 있는 경우, 메서드 수준의 설정이 우선합니다.

클래스 수준과 메서드 수준의 혼합 사용

클래스 수준과 메서드 수준의 @Transactional 애노테이션을 혼합하여 사용할 수 있습니다. 클래스 수준에서 기본 트랜잭션 설정을 적용하고, 특정 메서드에서 이를 재정의할 수 있습니다.

예제

import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly = true)
public class UserServiceImpl implements UserService {

    @Override
    public User getUser(Long id) {
        // 읽기 전용 트랜잭션 내에서 실행됨
        return userRepository.findById(id).orElse(null);
    }

    @Override
    @Transactional
    public void createUser(User user) {
        // 읽기 전용이 아닌 트랜잭션 내에서 실행됨
        userRepository.save(user);
    }
}

이 예제에서는 클래스 수준에서 @Transactional(readOnly = true)를 선언하여 기본적으로 모든 메서드가 읽기 전용 트랜잭션 내에서 실행되도록 설정하고, createUser 메서드에서는 읽기 전용이 아닌 트랜잭션을 적용하여 데이터를 수정할 수 있도록 설정했습니다.

비즈니스 로직 분리의 이점

  1. 코드의 가독성 향상: 트랜잭션 관리 코드를 비즈니스 로직에서 분리하여 코드의 가독성을 높입니다.
  2. 유지보수성 향상: 트랜잭션 설정을 중앙에서 관리할 수 있어 유지보수가 용이합니다.
  3. 일관성 보장: 트랜잭션 설정을 일관되게 적용하여 데이터베이스의 일관성과 무결성을 보장합니다.

이와 같이 @Transactional 애노테이션을 클래스 수준과 메서드 수준에서 적절히 사용하면 트랜잭션 관리를 유연하고 효율적으로 할 수 있으며, 비즈니스 로직을 명확하게 분리할 수 있습니다.

Citations: [1] https://stackoverflow.com/questions/23132822/what-is-the-difference-between-defining-transactional-on-class-vs-method [2] https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/annotations.html [3] https://www.geeksforgeeks.org/spring-boot-transaction-management-using-transactional-annotation/ [4] https://imiyoungman.tistory.com/9

 

[Spring] @Transactional의 이해

스프링에서 트랜잭션 처리를 위해 선언적 트랜잭션을 사용한다. 선언전 트랜잭션이란 설정 파일 or 어노테이션 방식으로 간편하게 트랜잭션에 관한 행위를 정의하는 것이다. (물론, 프로그래밍

imiyoungman.tistory.com

 

 

@Transactional 애노테이션을 사용하여 비즈니스 로직의 재시도 기능을 구현하는 방법은 무엇인가요

Spring의 @Transactional 애노테이션을 사용하여 비즈니스 로직의 재시도 기능을 구현하는 방법은 주로 트랜잭션이 실패했을 때 자동으로 재시도하는 메커니즘을 설정하는 것입니다. 이를 위해 Spring의 트랜잭션 관리와 AOP(Aspect-Oriented Programming)를 활용할 수 있습니다. 다음은 @Transactional 애노테이션을 사용하여 비즈니스 로직의 재시도 기능을 구현하는 방법을 단계별로 설명하겠습니다.

1. 기본 설정

먼저, Spring 애플리케이션에서 트랜잭션 관리를 활성화해야 합니다. 이를 위해 @EnableTransactionManagement 애노테이션을 사용합니다.

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class AppConfig {
    // 트랜잭션 관리 설정
}

2. 비즈니스 로직에 @Transactional 애노테이션 적용

비즈니스 로직이 포함된 서비스 클래스에 @Transactional 애노테이션을 적용합니다. 이 예제에서는 UserService 클래스의 createUser 메서드에 트랜잭션을 적용합니다.

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Transactional
    public void createUser(User user) {
        // 비즈니스 로직
        userRepository.save(user);
    }
}

3. 재시도 로직 구현

트랜잭션 실패 시 재시도 로직을 구현하기 위해 Spring AOP를 사용할 수 있습니다. 이를 위해 @Aspect 애노테이션을 사용하여 재시도 로직을 정의합니다.

3.1. 재시도 어드바이스 정의

재시도 로직을 포함하는 어드바이스를 정의합니다. 이 어드바이스는 트랜잭션이 실패할 때 지정된 횟수만큼 재시도합니다.

import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class RetryAspect {

    private static final int MAX_RETRIES = 3;

    @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
    public Object retry(ProceedingJoinPoint joinPoint) throws Throwable {
        int attempts = 0;
        Throwable lastException = null;

        while (attempts < MAX_RETRIES) {
            try {
                return joinPoint.proceed();
            } catch (Throwable e) {
                lastException = e;
                attempts++;
                if (attempts >= MAX_RETRIES) {
                    throw lastException;
                }
            }
        }
        throw lastException;
    }
}

3.2. AOP 설정

Spring AOP를 활성화하기 위해 @EnableAspectJAutoProxy 애노테이션을 사용합니다.

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    // AOP 설정
}

4. 예외 처리 및 롤백 설정

트랜잭션이 실패할 때 롤백을 설정하려면 @Transactional 애노테이션의 rollbackFor 속성을 사용하여 롤백 조건을 지정할 수 있습니다.

import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Transactional(rollbackFor = Exception.class)
    public void createUser(User user) throws Exception {
        // 비즈니스 로직
        userRepository.save(user);
    }
}

5. 전체 예제

위의 모든 설정을 종합하여 전체 예제를 구성하면 다음과 같습니다.

AppConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class AppConfig {
    // 트랜잭션 및 AOP 설정
}

UserService.java

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Transactional(rollbackFor = Exception.class)
    public void createUser(User user) throws Exception {
        // 비즈니스 로직
        userRepository.save(user);
    }
}

RetryAspect.java

import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class RetryAspect {

    private static final int MAX_RETRIES = 3;

    @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
    public Object retry(ProceedingJoinPoint joinPoint) throws Throwable {
        int attempts = 0;
        Throwable lastException = null;

        while (attempts < MAX_RETRIES) {
            try {
                return joinPoint.proceed();
            } catch (Throwable e) {
                lastException = e;
                attempts++;
                if (attempts >= MAX_RETRIES) {
                    throw lastException;
                }
            }
        }
        throw lastException;
    }
}

이와 같이 @Transactional 애노테이션과 Spring AOP를 사용하여 비즈니스 로직의 재시도 기능을 구현할 수 있습니다. 이를 통해 트랜잭션이 실패했을 때 자동으로 재시도하여 안정성을 높일 수 있습니다.

Citations: [1] https://ciit-training.com/en/2024/01/06/transactional-in-spring-how-it-works/ [2] https://www.geeksforgeeks.org/spring-boot-transaction-management-using-transactional-annotation/ [3] https://www.marcobehler.com/guides/spring-transaction-management-transactional-in-depth [4] https://stackoverflow.com/questions/3423972/spring-transaction-method-call-by-the-method-within-the-same-class-does-not-wo [5] https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/annotations.html [6] https://stackoverflow.com/questions/23132822/what-is-the-difference-between-defining-transactional-on-class-vs-method [7] https://stackoverflow.com/questions/41977173/spring-transactional-method-and-class

'개인 개발 공부 일지' 카테고리의 다른 글

MQTT  (0) 2024.07.02
nest.js  (0) 2024.07.02
JSP의 처리 과정, MVC 패턴, 쿠키와 세션  (0) 2024.06.24
HashMap 동작원리  (0) 2024.06.24
Java 예외처리  (0) 2024.06.24