<1> 이 내용을 통한 Benefit, 느낀점, 목표

이 코드를 통해 얻을 수 있는 Benefit(이점), 느낀 점, 그리고 목표를 설명드리겠습니다.

1. Benefit (이점):

  • 스프링의 데이터베이스 관리 효율성:

    • 이 코드를 통해 스프링 프레임워크가 제공하는 데이터베이스 설정JPA를 활용한 객체-관계 매핑을 배울 수 있다. 데이터 소스, 트랜잭션 관리, Hibernate 설정 등 복잡한 설정을 간단하고 체계적으로 처리할 수 있다.
    • 특히 HikariCP와 같은 커넥션 풀을 사용해 데이터베이스와의 연결을 효율적으로 관리함으로써, 애플리케이션의 성능과 확장성을 높일 수 있다.
  • 외부 설정 관리:

    • application.properties와 같은 외부 설정 파일을 사용하여, 코드에서 하드코딩을 줄이고 설정 값을 유연하게 관리할 수 있다. 이로 인해 환경 변화나 데이터베이스 연결 정보의 변경에도 쉽게 대응할 수 있다.
  • 트랜잭션 관리의 용이성:

    • @EnableTransactionManagementPlatformTransactionManager를 통해 트랜잭션을 일관되게 관리하고, 데이터 일관성과 무결성을 유지하는 방법을 배운다. 트랜잭션 관리는 데이터베이스 작업에서 매우 중요한 부분으로, 이 설정이 자동으로 이루어진다는 점이 큰 이점이다.
  • Hibernate와 JPA의 통합:

    • 스프링이 제공하는 JPA 기능을 통해 객체-관계 매핑(ORM)을 쉽게 적용할 수 있다. 이 코드는 데이터베이스와 상호작용할 때 복잡한 SQL 쿼리 대신 JPA 리포지토리를 사용하여 더 간결한 코드를 작성할 수 있게 도와준다.

2. 느낀 점:

  • 스프링의 유연성 및 확장성:

    • 스프링이 제공하는 다양한 설정과 확장 기능이 매우 유연하다는 것을 느낄 수 있었다. 트랜잭션, 데이터베이스 연결, JPA 등 복잡한 설정을 간단한 어노테이션과 설정 파일을 통해 처리할 수 있어서 유지보수와 확장성에 큰 도움이 된다는 점을 알게 되었다.
  • 외부 설정의 중요성:

    • @PropertySource@Value 어노테이션을 통해 외부 설정 파일을 활용하는 방식이 애플리케이션의 유연성과 유지보수성을 크게 높여준다. 설정 값을 코드에서 하드코딩하지 않고 외부 파일로 분리하여 관리하는 것이 얼마나 중요한지 다시 한번 깨닫게 되었다.
  • 보안과 연결 관리의 중요성:

    • 데이터베이스와의 연결에서 HikariCP와 같은 커넥션 풀을 사용하여 성능을 최적화하는 방법과 트랜잭션 관리를 통해 데이터의 일관성을 유지하는 것이 얼마나 중요한지 느꼈다. 특히 대규모 애플리케이션에서 이러한 설정들이 필수적이라는 점을 깨달았다.

3. 목표:

  • 스프링 프레임워크 심화 학습:

    • 이번 코드를 통해 스프링 프레임워크의 핵심 설정JPA 사용법을 이해했으므로, 앞으로 더 복잡한 설정과 고급 기능을 학습하고 실제 프로젝트에 적용하는 것이 목표입니다. 예를 들어, 더 복잡한 트랜잭션 관리나 고급 Hibernate 기능을 활용할 수 있도록 심화된 지식을 쌓고 싶습니다.
  • 효율적인 데이터베이스 관리 시스템 구축:

    • 이 코드를 바탕으로 데이터베이스 성능 최적화확장성 있는 시스템 구축을 목표로 삼을 수 있습니다. 특히 HikariCP와 같은 커넥션 풀을 더 깊이 이해하고, 이를 활용해 데이터베이스 연결 성능을 최대화할 계획입니다.
  • 코드 가독성과 유지보수성 향상:

    • 외부 설정 파일 관리, JPA의 ORM 사용 등으로 인해 코드가 더 깔끔해지고 유지보수성이 좋아진다는 점을 느꼈습니다. 앞으로도 이러한 방식을 활용해 가독성 좋고 유지보수가 용이한 코드를 작성하는 것을 목표로 삼을 것입니다.
  • 보안과 성능을 고려한 애플리케이션 설계:

    • 데이터베이스 연결 관리나 트랜잭션 처리에서 보안과 성능을 고려한 설계를 하여, 더 안정적이고 효율적인 애플리케이션을 구축할 수 있는 능력을 키우는 것이 목표입니다.

이러한 이점과 목표를 통해 더 효율적이고 확장성 있는 애플리케이션을 개발하고, 스프링 프레임워크의 다양한 기능을 실제 프로젝트에서 적극 활용하는 개발자가 되는 것을 목표로 할 수 있습니다.


<[Config] DBConfig>

package org.project.backend.config;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;

/**
 * 데이터베이스 설정을 관리하는 클래스.
 * JPA, 트랜잭션 관리, 데이터 소스 설정을 포함한다.
 */
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "org.project.backend.repository")
@PropertySource("classpath:application.properties")
public class DBConfig {

    /**
     * 엔티티 매니저 팩토리를 설정하고 Hibernate 관련 속성을 추가한다.
     *
     * @param dataSource 데이터 소스 (HikariCP)
     * @param ddlAuto hibernate.ddl-auto 설정 값 (application.properties에서 읽어옴)
     * @param dialect hibernate.dialect 설정 값 (application.properties에서 읽어옴)
     * @return LocalContainerEntityManagerFactoryBean 객체
     */
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
                                                                       @Value("${spring.jpa.hibernate.ddl-auto}") String ddlAuto,
                                                                       @Value("${spring.jpa.properties.hibernate.dialect}") String dialect) {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan("org.project.backend.model"); // 엔티티가 위치한 패키지
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        // Hibernate 설정 추가
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", ddlAuto);
        properties.setProperty("hibernate.dialect", dialect);
        em.setJpaProperties(properties);

        return em;
    }

    /**
     * HikariCP를 이용한 데이터 소스를 설정한다.
     * MySQL 데이터베이스에 연결되며, 연결 풀의 최대 크기는 10으로 설정된다.
     * HikariCP를 쓰는 이유 : https://github.com/brettwooldridge/HikariCP-benchmark
     *
     * @return DataSource 객체 (HikariDataSource)
     */
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setDriverClassName("com.mysql.cj.jdbc.Driver");
        config.setJdbcUrl("jdbc:mysql://localhost:3306/baenang");
        config.setUsername("root");
        config.setPassword("1234");
        config.setMaximumPoolSize(10); // 최대 커넥션 풀 크기
        return new HikariDataSource(config);
    }

    /**
     * 트랜잭션 매니저를 설정한다.
     * EntityManagerFactory를 통해 JPA 트랜잭션을 관리한다.
     *
     * @param entityManagerFactory 엔티티 매니저 팩토리
     * @return PlatformTransactionManager 객체
     */
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }
}

<2> 코드 설명

이 코드는 스프링 프레임워크에서 데이터베이스 설정, JPA(Entity 매니저) 및 트랜잭션 관리를 담당하는 구성 파일입니다. 각 줄의 자바 및 스프링 개념을 설명하겠습니다.

1. 패키지 선언

package org.project.backend.config;
  • 기능: 이 클래스가 org.project.backend.config 패키지에 포함되어 있음을 나타낸다.
  • 논리 구조: 패키지는 관련된 클래스들을 그룹화하여 유지보수성을 높인다.
  • 상호작용: 패키지 내 다른 클래스들과 상호작용하고, 외부 클래스는 임포트를 통해 상호작용할 수 있다.

2. 클래스 임포트

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
  • 기능: HikariCP, JPA, 트랜잭션 관리 및 데이터베이스 설정에 필요한 클래스들을 임포트한다.
  • 논리 구조: 외부 라이브러리나 스프링 프레임워크의 클래스를 가져와 설정을 구성한다.
  • 상호작용: 각각의 클래스와 상호작용하며, 데이터베이스 연결, 트랜잭션 관리 등을 처리한다.

3. 클래스 선언 및 어노테이션

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "org.project.backend.repository")
@PropertySource("classpath:application.properties")
public class DBConfig {
  • 기능:
    이 클래스가 스프링의 구성 클래스임을 나타내고, 트랜잭션 관리와 JPA 리포지토리 활성화, 외부 프로퍼티 파일(application.properties)의 사용을 명시한다.
  • 논리 구조:
    @Configuration으로 해당 클래스가 스프링 컨텍스트에 빈(bean)으로 등록되고, @EnableTransactionManagement로 트랜잭션 관리가 활성화된다.
  • 상호작용:
    application.properties 파일에서 설정 값을 가져오고, org.project.backend.repository 패키지의 JPA 리포지토리와 상호작용한다.

4. LocalContainerEntityManagerFactoryBean 빈 선언

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
                                                                   @Value("${spring.jpa.hibernate.ddl-auto}") String ddlAuto,
                                                                   @Value("${spring.jpa.properties.hibernate.dialect}") String dialect) {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource);
    em.setPackagesToScan("org.project.backend.model"); // 엔티티가 위치한 패키지
    em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

    Properties properties = new Properties();
    properties.setProperty("hibernate.hbm2ddl.auto", ddlAuto);
    properties.setProperty("hibernate.dialect", dialect);
    em.setJpaProperties(properties);

    return em;
}
  • 기능:
    JPA의 EntityManagerFactory를 설정하고, 데이터 소스와 Hibernate 관련 속성을 설정한다.
  • 논리 구조:
    엔티티 매니저는 JPA가 데이터베이스와 상호작용하는 핵심 컴포넌트이다. @Value를 통해 application.properties에서 Hibernate 설정을 가져온다.
  • 상호작용:
    HikariDataSourceapplication.properties 파일의 설정 값과 상호작용하며, org.project.backend.model 패키지에 있는 엔티티 클래스를 스캔한다.

5. DataSource 빈 선언

@Bean
public DataSource dataSource() {
    HikariConfig config = new HikariConfig();
    config.setDriverClassName("com.mysql.cj.jdbc.Driver");
    config.setJdbcUrl("jdbc:mysql://localhost:3306/baenang");
    config.setUsername("root");
    config.setPassword("1234");
    config.setMaximumPoolSize(10); // 최대 커넥션 풀 크기
    return new HikariDataSource(config);
}
  • 기능:
    HikariCP를 사용한 데이터 소스를 설정하며, MySQL과 연결한다.
  • 논리 구조:
    데이터베이스 연결 풀 관리 도구인 HikariCP를 사용해 성능을 최적화하고, 데이터베이스 연결을 효율적으로 관리한다.
  • 상호작용:
    MySQL 데이터베이스와 상호작용하며, 애플리케이션에서 데이터베이스에 접근할 때 이 데이터 소스를 사용한다.

6. PlatformTransactionManager 빈 선언

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
}
  • 기능:
    트랜잭션 관리를 설정하며, EntityManagerFactory를 통해 JPA 트랜잭션을 관리한다.
  • 논리 구조:
    트랜잭션 관리는 데이터 일관성을 유지하기 위해 필수적이며, JPA 트랜잭션 매니저는 JPA 기반 트랜잭션을 처리한다.
  • 상호작용:
    EntityManagerFactory와 상호작용하며, 데이터베이스 작업이 원자성을 유지하도록 트랜잭션을 관리한다.

추가 설명:

1. @Value 어노테이션:

  • @Value는 외부 설정 파일에서 값을 읽어와 해당 변수에 주입하는 역할을 한다. 이 예제에서는 spring.jpa.hibernate.ddl-autospring.jpa.properties.hibernate.dialect 값을 가져와 Hibernate의 속성을 설정한다.

2. LocalContainerEntityManagerFactoryBean:

  • 이 클래스는 JPA EntityManagerFactory를 생성하는 데 사용된다. 데이터 소스와 Hibernate 설정을 통해 데이터베이스와 엔티티 객체 간의 매핑을 설정합니다.

3. HikariCP:

  • HikariCP는 자바 애플리케이션에서 널리 사용하는 커넥션 풀링 라이브러리로, 빠르고 경량화된 성능을 제공합니다. 이 코드에서는 MySQL 데이터베이스와 연결되며, 연결 풀의 최대 크기는 10으로 설정되었습니다.

4. 트랜잭션 관리:

  • 트랜잭션 관리는 데이터베이스 작업을 처리할 때 중간에 실패할 경우 롤백하거나, 성공할 경우 커밋하는 중요한 역할을 합니다. PlatformTransactionManager는 JPA 트랜잭션을 관리하기 위해 사용됩니다.

결론:

이 코드는 데이터베이스 설정, JPA 엔티티 매니저 팩토리 및 트랜잭션 관리에 필요한 구성을 모두 포함하고 있습니다. 이러한 설정은 스프링 프레임워크를 사용하는 애플리케이션에서 데이터베이스와의 상호작용을 관리하며, 특히 트랜잭션의 원자성을 보장하여 데이터 일관성을 유지하는 중요한 역할을 합니다.

이 코드 구조를 이해하면 스프링 애플리케이션에서 데이터베이스 설정과 트랜잭션 관리를 어떻게 구성하고 효율적으로 처리할 수 있는지 배우게 됩니다.


<3> Hibernate 기능이란?

Hibernate는 자바에서 널리 사용되는 ORM(Object-Relational Mapping) 프레임워크로, 자바 객체와 관계형 데이터베이스 간의 매핑을 자동으로 처리해 주는 도구입니다. ORM은 객체 지향 프로그래밍 언어의 객체와 관계형 데이터베이스의 테이블 간의 불일치를 해결해 주는 역할을 합니다. Hibernate는 JPA(Java Persistence API) 표준을 구현한 가장 대표적인 프레임워크 중 하나입니다. 주요 기능은 다음과 같습니다.

1. ORM (객체-관계 매핑)

  • 기능: 자바 객체(엔티티)와 데이터베이스 테이블 간의 매핑을 설정하여 객체 지향 프로그래밍과 관계형 데이터베이스 간의 불일치를 해결합니다.
  • 장점: 개발자가 SQL 쿼리를 직접 작성하지 않아도, 자바 객체를 통해 데이터베이스와 상호작용할 수 있습니다.

2. HQL (Hibernate Query Language)

  • 기능: SQL과 비슷하지만 자바 객체(Entity)를 대상으로 하는 쿼리 언어입니다. 객체 지향적인 방식으로 데이터베이스 질의를 작성할 수 있습니다.
  • 장점: 데이터베이스 테이블이 아닌 엔티티 객체를 기준으로 질의를 작성하므로 코드가 더 직관적입니다.

3. 지연 로딩(Lazy Loading)

  • 기능: 엔티티 객체를 처음 조회할 때 관련 데이터를 즉시 가져오지 않고, 실제로 필요할 때(필드에 접근할 때) 데이터를 로드하는 방식입니다.
  • 장점: 성능 최적화를 돕고, 불필요한 데이터베이스 접근을 줄입니다.

4. 캐싱(Caching)

  • 1차 캐시: 엔티티 매니저가 관리하는 캐시로, 같은 트랜잭션 내에서 동일한 엔티티를 조회할 경우 데이터베이스에서 다시 조회하지 않고 캐시된 데이터를 사용합니다.
  • 2차 캐시: 애플리케이션 전체에서 사용할 수 있는 캐시로, 여러 트랜잭션 간에도 엔티티를 캐싱할 수 있습니다.
  • 장점: 캐싱을 통해 성능을 크게 개선할 수 있습니다.

5. 자동 테이블 생성

  • 기능: Hibernate는 데이터베이스 테이블을 자동으로 생성하고 관리하는 기능을 제공합니다. 개발자가 엔티티 클래스를 작성하면, 설정에 따라 데이터베이스 테이블이 자동으로 생성됩니다.
  • 장점: 초기 개발 단계에서 데이터베이스 스키마를 수동으로 관리할 필요 없이 자동으로 생성, 수정할 수 있습니다.

6. 자동 변경 감지 (Dirty Checking)

  • 기능: Hibernate는 엔티티 객체의 상태 변화를 감지하고, 트랜잭션 종료 시 자동으로 변경된 내용을 데이터베이스에 반영합니다.
  • 장점: 개발자가 명시적으로 UPDATE SQL을 작성하지 않아도, 객체 상태 변화만으로 데이터베이스에 변경 사항이 자동 반영됩니다.

7. 트랜잭션 관리

  • 기능: Hibernate는 데이터베이스와의 상호작용에서 트랜잭션 관리를 지원합니다. 데이터베이스 작업이 실패하면 롤백하고, 성공하면 커밋하는 방식으로 작업의 일관성을 보장합니다.
  • 장점: 데이터 무결성과 트랜잭션 원자성을 보장하여 안전한 데이터베이스 작업이 가능합니다.

8. 연관 관계 매핑

  • 기능: Hibernate는 엔티티 간의 1:1, 1:다, 다:1, 다:다와 같은 다양한 연관 관계를 매핑할 수 있습니다.
  • 장점: 객체 지향적인 관계를 데이터베이스에서도 직관적으로 표현할 수 있게 해줍니다.

Hibernate의 장점

  1. 생산성 향상: SQL을 작성하지 않고도 객체 지향적인 방식으로 데이터베이스와 상호작용할 수 있습니다.
  2. 유지보수성 증가: 객체와 데이터베이스 간의 매핑이 자동으로 관리되므로, 유지보수 작업이 단순해집니다.
  3. 데이터베이스 독립성: 특정 데이터베이스 시스템에 종속되지 않고, 다양한 데이터베이스에서 사용할 수 있습니다.
  4. 성능 최적화: 캐싱, 지연 로딩 등을 통해 애플리케이션의 성능을 최적화할 수 있습니다.

Hibernate는 자바 애플리케이션에서 데이터베이스와의 상호작용을 단순화하고, 개발 생산성을 높이며, 유지보수를 쉽게 해주는 강력한 도구입니다.


<4> 트랜잭션 관리란?

트랜잭션 관리는 데이터베이스 작업을 안전하게 처리하기 위한 중요한 개념으로, 여러 작업이 하나의 논리적인 단위로 묶여 수행되는 것을 보장하는 프로세스를 말합니다. 트랜잭션 관리의 핵심 목적은 데이터의 일관성, 무결성, 신뢰성을 유지하는 것입니다. 트랜잭션 관리의 기본 개념과 동작 방식, 스프링에서의 구현 방식에 대해 설명하겠습니다.

1. 트랜잭션(Transaction)이란?

트랜잭션은 하나의 일련의 데이터베이스 작업을 묶어서 하나의 작업처럼 처리하는 것을 말합니다. 트랜잭션 내에서 수행되는 모든 작업은 성공적으로 완료되거나(Commit), 실패 시 전부 취소(Rollback)되는 특성을 가집니다. 즉, 여러 데이터베이스 작업이 트랜잭션으로 묶여 있으면, 그 중 하나라도 실패하면 전체 작업이 취소됩니다.

2. 트랜잭션의 4가지 속성 (ACID)

트랜잭션이 안전하게 처리되기 위해서는 ACID 속성을 만족해야 합니다:

  • 원자성(Atomicity): 트랜잭션 내의 모든 작업이 완전히 수행되거나, 전혀 수행되지 않아야 합니다. 일부만 처리되는 경우는 없습니다.
  • 일관성(Consistency): 트랜잭션이 완료된 후, 데이터베이스는 항상 일관된 상태를 유지해야 합니다. 데이터의 무결성이 보장됩니다.
  • 격리성(Isolation): 하나의 트랜잭션이 실행되는 동안 다른 트랜잭션의 영향을 받지 않도록 해야 합니다.
  • 지속성(Durability): 트랜잭션이 성공적으로 완료되면, 그 결과는 영구적으로 데이터베이스에 반영되어야 합니다.

3. 트랜잭션 관리의 역할

트랜잭션 관리는 이 ACID 속성을 보장하면서 데이터베이스 작업을 관리합니다. 주요 역할은 다음과 같습니다:

  • 커밋(Commit): 트랜잭션이 성공적으로 완료되면, 모든 변경 사항을 데이터베이스에 반영합니다.
  • 롤백(Rollback): 트랜잭션 중 오류가 발생하거나, 중간에 문제가 생기면 모든 변경 사항을 취소하고 데이터베이스 상태를 트랜잭션 시작 전으로 되돌립니다.

4. 스프링에서의 트랜잭션 관리

스프링 프레임워크는 선언적 트랜잭션 관리프로그래밍 방식 트랜잭션 관리를 모두 지원합니다. 스프링에서는 주로 선언적 트랜잭션 관리가 사용됩니다.

1) 선언적 트랜잭션 관리

스프링에서 선언적 트랜잭션 관리는 트랜잭션을 직접 제어할 필요 없이, 어노테이션을 통해 트랜잭션을 관리합니다. 트랜잭션 처리를 해야 하는 메소드에 @Transactional 어노테이션을 사용하여 트랜잭션 경계를 설정합니다.

  • Example:
    @Transactional
    public void updateAccountBalance(Long accountId, Double amount) {
        Account account = accountRepository.findById(accountId);
        account.setBalance(account.getBalance() + amount);
        accountRepository.save(account);
    }
    위의 코드에서는 updateAccountBalance 메소드가 트랜잭션으로 감싸져 있으며, 이 메소드 내에서 오류가 발생하면 롤백이 됩니다.

2) 프로그래밍 방식 트랜잭션 관리

프로그래밍 방식 트랜잭션 관리는 개발자가 트랜잭션을 명시적으로 시작하고, 커밋이나 롤백을 직접 처리하는 방식입니다. 보통 PlatformTransactionManager 인터페이스를 사용하여 트랜잭션을 관리합니다.

  • Example:

    @Autowired
    private PlatformTransactionManager transactionManager;
    
    public void performTransaction() {
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
    
        try {
            // 비즈니스 로직 수행
            transactionManager.commit(status);  // 성공 시 커밋
        } catch (Exception e) {
            transactionManager.rollback(status);  // 실패 시 롤백
        }
    }

    이 방식은 직접 트랜잭션 경계를 지정하고 제어할 수 있지만, 코드가 복잡해질 수 있습니다.

5. 트랜잭션 격리 수준(Isolation Level)

트랜잭션 격리 수준은 여러 트랜잭션이 동시에 처리될 때 서로 간의 영향을 최소화하기 위해 설정됩니다. 격리 수준이 높을수록 트랜잭션 간의 간섭은 줄어들지만, 성능이 떨어질 수 있습니다. 스프링에서는 @Transactional 어노테이션에서 격리 수준을 설정할 수 있습니다.

  • 격리 수준 종류:
    • READ_UNCOMMITTED: 커밋되지 않은 데이터도 읽을 수 있음(가장 낮은 수준).
    • READ_COMMITTED: 커밋된 데이터만 읽을 수 있음(기본 수준).
    • REPEATABLE_READ: 트랜잭션 내에서 읽은 데이터는 항상 동일하게 유지됨.
    • SERIALIZABLE: 가장 엄격한 격리 수준으로, 트랜잭션 간에 완전한 독립성을 보장.

6. 트랜잭션 전파(Propagation)

스프링에서는 트랜잭션이 호출되는 메소드 간에 어떻게 전파될지 결정하는 전파(Propagation) 속성을 설정할 수 있습니다. 예를 들어, 트랜잭션을 호출하는 메소드와 호출된 메소드가 각각 독립적인 트랜잭션을 가질 것인지, 아니면 하나의 트랜잭션으로 묶일 것인지를 결정합니다.

  • 전파 속성 종류:
    • REQUIRED: 기본값으로, 현재 트랜잭션이 있으면 해당 트랜잭션을 사용하고, 없으면 새 트랜잭션을 생성합니다.
    • REQUIRES_NEW: 항상 새로운 트랜잭션을 생성합니다.
    • MANDATORY: 기존 트랜잭션이 반드시 있어야 합니다. 없으면 예외가 발생합니다.

7. 트랜잭션 관리의 중요성

트랜잭션 관리는 애플리케이션에서 매우 중요합니다. 특히 다음과 같은 상황에서 필수적입니다:

  • 데이터 일관성 유지: 데이터베이스 작업 중 하나라도 실패하면 전체 작업이 롤백되기 때문에, 데이터의 일관성을 보장할 수 있습니다.
  • 복구 가능성: 오류 발생 시 이전 상태로 되돌릴 수 있으므로, 애플리케이션의 안정성이 높아집니다.
  • 동시성 제어: 여러 사용자가 동시에 데이터베이스에 접근할 때, 트랜잭션 격리 수준을 통해 데이터 간섭을 최소화할 수 있습니다.

결론:

트랜잭션 관리는 데이터베이스 작업을 안전하고 일관성 있게 처리하기 위한 핵심적인 메커니즘입니다. 트랜잭션을 통해 오류 발생 시 롤백하여 데이터 무결성을 유지하고, 여러 작업이 하나의 단위로 실행되도록 보장할 수 있습니다. 스프링에서는 @Transactional 어노테이션을 사용하여 선언적으로 쉽게 트랜잭션 관리를 할 수 있어, 코드의 복잡성을 줄이면서 안정성을 높일 수 있습니다.


<5> HikariCP이란?

HikariCP는 자바 애플리케이션에서 사용하는 JDBC 커넥션 풀링(Connection Pooling) 라이브러리입니다. 커넥션 풀링은 데이터베이스와 애플리케이션 간의 연결을 효율적으로 관리하기 위한 기법으로, HikariCP는 특히 빠르고 경량이라는 장점 때문에 많이 사용됩니다. HikariCP는 성능과 자원 효율성 면에서 뛰어나서 많은 자바 기반 웹 애플리케이션에서 선택되는 커넥션 풀링 솔루션입니다.

1. 커넥션 풀링(Connection Pooling)이란?

커넥션 풀링은 데이터베이스에 연결을 요청할 때마다 새로운 연결을 생성하는 대신, 미리 일정 수의 연결을 생성해 놓고, 필요할 때마다 이를 재사용하는 기법입니다. 이를 통해 데이터베이스와의 연결을 효율적으로 관리하고, 성능을 크게 향상시킬 수 있습니다.

  • 문제점: 각 요청마다 새로운 연결을 생성하고 닫는 작업은 매우 비용이 많이 듭니다. 이러한 작업이 반복되면 성능 저하를 초래합니다.
  • 해결책: 커넥션 풀을 사용하면, 미리 생성된 커넥션을 재사용함으로써 새 연결을 만드는 시간을 줄이고 시스템의 성능을 높일 수 있습니다.

2. HikariCP의 주요 특징

1) 고성능

  • HikariCP는 매우 빠른 커넥션 풀링 라이브러리로, 다른 커넥션 풀 라이브러리들보다 더 낮은 지연 시간과 높은 처리량을 제공합니다.
  • 실제로 HikariCP는 다양한 벤치마크에서 최고의 성능을 보이는 커넥션 풀로 평가됩니다.

2) 경량성

  • HikariCP는 필요한 최소한의 기능만을 포함하고 있어서 매우 가볍습니다. 이로 인해 메모리 사용량이 적고, 빠르게 동작합니다.

3) 빠른 커넥션 회복

  • 커넥션이 실패하거나 유휴 상태일 때, 빠르게 회복하거나 커넥션을 교체하는 메커니즘을 가지고 있습니다. 이는 데이터베이스 연결 문제가 발생할 때 더 빠르게 복구될 수 있도록 도와줍니다.

4) 최소 설정

  • HikariCP는 기본적으로 성능이 최적화되어 있어, 추가적인 복잡한 설정 없이도 바로 사용할 수 있습니다. 필요한 경우 특정 설정을 통해 세밀한 튜닝이 가능합니다.

5) 안정성

  • HikariCP는 대규모 트래픽이 몰리는 환경에서도 안정적으로 작동하며, 매우 낮은 대기 시간으로 많은 양의 연결을 처리할 수 있습니다.

3. HikariCP의 주요 설정

HikariCP는 설정을 통해 커넥션 풀의 동작을 조정할 수 있습니다. 주요 설정 항목은 다음과 같습니다.

  • jdbcUrl: 데이터베이스의 JDBC URL을 설정합니다. 예를 들어, jdbc:mysql://localhost:3306/mydb와 같이 설정할 수 있습니다.
  • username: 데이터베이스에 연결할 사용자 이름을 설정합니다.
  • password: 데이터베이스에 연결할 사용자 비밀번호를 설정합니다.
  • maximumPoolSize: 풀에서 유지할 수 있는 최대 커넥션 수를 설정합니다. 기본값은 10이며, 애플리케이션의 부하에 따라 설정할 수 있습니다.
  • minimumIdle: 풀에서 유지할 수 있는 최소 유휴 커넥션 수를 설정합니다. 유휴 커넥션이 이 값보다 적으면 새로운 커넥션을 생성합니다.
  • connectionTimeout: 커넥션을 얻기 위해 기다릴 수 있는 최대 시간을 설정합니다. 이 시간이 지나면 예외가 발생합니다.
  • idleTimeout: 유휴 상태의 커넥션이 일정 시간 동안 사용되지 않으면 커넥션을 제거합니다.
  • poolName: 풀에 이름을 설정할 수 있습니다. 기본값은 자동으로 생성됩니다.

4. HikariCP 사용 예시

Spring Boot에서 HikariCP를 사용하는 방법을 간단히 설명하면 다음과 같습니다. Spring Boot에서는 기본적으로 HikariCP를 사용하도록 설정되어 있습니다.

application.properties 예시:

spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/mydb
spring.datasource.hikari.username=root
spring.datasource.hikari.password=1234
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.pool-name=MyHikariCP

Java 코드에서 직접 설정:

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import javax.sql.DataSource;

public class DataSourceConfig {

    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        config.setUsername("root");
        config.setPassword("1234");
        config.setMaximumPoolSize(10);  // 최대 커넥션 풀 크기
        config.setMinimumIdle(5);  // 최소 유휴 커넥션 수
        config.setConnectionTimeout(30000);  // 커넥션 요청 시 대기 시간

        return new HikariDataSource(config);
    }
}

5. HikariCP의 장점

  • 빠른 커넥션 생성: 최소한의 시간으로 커넥션을 생성하고 제공.
  • 낮은 메모리 사용량: 경량화된 커넥션 풀로 시스템 자원을 적게 사용.
  • 안정성: 많은 양의 트래픽을 처리할 수 있고, 에러가 발생해도 신속하게 회복 가능.
  • 최소한의 설정: 기본 설정으로도 최적의 성능을 제공하며, 복잡한 설정이 필요 없습니다.

6. HikariCP를 사용하는 이유

  1. 높은 성능: 특히 대규모 트래픽을 처리해야 하는 애플리케이션에서 성능 면에서 큰 장점이 있습니다.
  2. 효율적인 자원 사용: 메모리와 CPU 자원을 효율적으로 사용하여 경량화된 애플리케이션을 구현할 수 있습니다.
  3. 유연한 설정: 기본적으로 최적화되어 있지만, 애플리케이션의 요구에 맞게 세부 설정을 조정할 수 있습니다.
  4. 안정적인 트랜잭션 처리: 안정적인 커넥션 관리를 통해 트랜잭션 처리 시 성능 저하나 실패를 최소화할 수 있습니다.

결론:

HikariCP는 빠르고 가벼운 커넥션 풀링 라이브러리로, 성능이 중요한 자바 애플리케이션에서 사용하기 적합합니다. 높은 성능과 안정성, 간단한 설정으로 인해 많은 개발자들이 선택하고 있으며, 특히 트랜잭션 처리나 고부하 시스템에서 매우 유용합니다.

0개의 댓글