AI 지식 / / 2025. 10. 10. 06:39

[Spring Boot 번역] Data Access

이 버전은 아직 개발 중이며 안정적이지 않습니다. 최신 안정 버전은 Spring Boot 3.5.6을 사용하세요!

Data Access

Spring Boot는 데이터 소스 작업을 위한 다양한 스타터를 포함하고 있습니다.
이 섹션은 이와 관련된 질문에 답변합니다.

커스텀 DataSource 구성하기

자체 DataSource를 구성하려면, 구성에서 해당 타입의 @Bean을 정의하세요.
Spring Boot는 데이터베이스 초기화를 포함하여 DataSource가 필요한 모든 곳에서 이를 재사용합니다.
일부 설정을 외부화해야 하는 경우, DataSource를 환경에 바인딩할 수 있습니다 (Third-party Configuration 참조).

다음 예제는 bean에서 데이터 소스를 정의하는 방법을 보여줍니다:

Java:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource")
    public SomeDataSource dataSource() {
        return new SomeDataSource();
    }

}

Kotlin:

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource")
    fun dataSource(): SomeDataSource {
        return SomeDataSource()
    }

}

다음 예제는 속성을 설정하여 데이터 소스를 정의하는 방법을 보여줍니다:

Properties:

app.datasource.url=jdbc:h2:mem:mydb
app.datasource.username=sa
app.datasource.pool-size=30

YAML:

app:
  datasource:
    url: "jdbc:h2:mem:mydb"
    username: "sa"
    pool-size: 30

SomeDataSource가 URL, username, pool size에 대한 일반 JavaBean 속성을 가지고 있다고 가정하면, 이러한 설정은 DataSource가 다른 컴포넌트에 제공되기 전에 자동으로 바인딩됩니다.

Spring Boot는 DataSourceBuilder라는 유틸리티 빌더 클래스도 제공하며, 이는 표준 데이터 소스 중 하나를 생성하는 데 사용할 수 있습니다 (클래스패스에 있는 경우).
빌더는 클래스패스에서 사용 가능한 것을 기반으로 어떤 것을 사용할지 감지할 수 있습니다.
또한 JDBC URL을 기반으로 드라이버를 자동 감지합니다.

다음 예제는 DataSourceBuilder를 사용하여 데이터 소스를 생성하는 방법을 보여줍니다:

Java:

import javax.sql.DataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

}

Kotlin:

import javax.sql.DataSource

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.DataSourceBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource")
    fun dataSource(): DataSource {
        return DataSourceBuilder.create().build()
    }

}

해당 DataSource로 앱을 실행하려면 연결 정보만 있으면 됩니다.
풀 관련 설정도 제공할 수 있습니다.
자세한 내용은 런타임에 사용될 구현을 확인하세요.

다음 예제는 속성을 설정하여 JDBC 데이터 소스를 정의하는 방법을 보여줍니다:

Properties:

app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30

YAML:

app:
  datasource:
    url: "jdbc:mysql://localhost/test"
    username: "dbuser"
    password: "dbpass"
    pool-size: 30

그러나 메서드의 DataSource 반환 타입으로 인해 문제가 있습니다.
이는 커넥션 풀의 실제 타입을 숨기므로 커스텀 DataSource에 대한 구성 속성 메타데이터가 생성되지 않으며 IDE에서 자동 완성을 사용할 수 없습니다.
이 문제를 해결하려면 빌더의 type(Class) 메서드를 사용하여 빌드할 DataSource의 타입을 지정하고 메서드의 반환 타입을 업데이트하세요.
예를 들어, 다음은 DataSourceBuilderHikariDataSource를 생성하는 방법을 보여줍니다:

Java:

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource")
    public HikariDataSource dataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

}

Kotlin:

import com.zaxxer.hikari.HikariDataSource
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.DataSourceBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource")
    fun dataSource(): HikariDataSource {
        return DataSourceBuilder.create().type(HikariDataSource::class.java).build()
    }

}

안타깝게도 이 기본 설정은 작동하지 않습니다. Hikari에는 url 속성이 없기 때문입니다.
대신 jdbc-url 속성이 있으므로 다음과 같이 구성을 다시 작성해야 합니다:

Properties:

app.datasource.jdbc-url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30

YAML:

app:
  datasource:
    jdbc-url: "jdbc:mysql://localhost/test"
    username: "dbuser"
    password: "dbpass"
    pool-size: 30

이 문제를 해결하려면 DataSourceProperties를 사용하세요. 이는 url에서 jdbc-url로의 변환을 처리합니다.
initializeDataSourceBuilder() 메서드를 사용하여 DataSourceProperties 객체의 상태에서 DataSourceBuilder를 초기화할 수 있습니다.
Spring Boot가 자동으로 생성하는 DataSourceProperties를 주입할 수 있지만, 이렇게 하면 spring.datasource.*app.datasource.*에 구성이 분산됩니다.
이를 피하려면 다음 예제와 같이 커스텀 구성 속성 접두사를 사용하여 커스텀 DataSourceProperties를 정의하세요:

Java:

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties("app.datasource.configuration")
    public HikariDataSource dataSource(DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

}

Kotlin:

import com.zaxxer.hikari.HikariDataSource
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary

@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource")
    fun dataSourceProperties(): DataSourceProperties {
        return DataSourceProperties()
    }

    @Bean
    @ConfigurationProperties("app.datasource.configuration")
    fun dataSource(properties: DataSourceProperties): HikariDataSource {
        return properties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
    }

}

이 설정은 Spring Boot가 기본적으로 수행하는 것과 동일하지만, 풀의 타입이 코드에 지정되고 설정이 app.datasource.configuration.* 속성으로 노출된다는 점이 다릅니다.
DataSourcePropertiesurl에서 jdbc-url로의 변환을 처리하므로 다음과 같이 구성할 수 있습니다:

Properties:

app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30

YAML:

app:
  datasource:
    url: "jdbc:mysql://localhost/test"
    username: "dbuser"
    password: "dbpass"
    configuration:
      maximum-pool-size: 30

커스텀 구성이 코드에서 Hikari를 사용하도록 지정하므로 app.datasource.type은 효과가 없습니다.

Supported Connection Pools에 설명된 대로, DataSourceBuilder는 여러 다른 커넥션 풀을 지원합니다.
Hikari 이외의 풀을 사용하려면 클래스패스에 추가하고 type(Class) 메서드를 사용하여 사용할 풀 클래스를 지정하고 @Bean 메서드의 반환 타입을 일치하도록 업데이트하세요.
이렇게 하면 선택한 특정 커넥션 풀에 대한 구성 속성 메타데이터도 제공됩니다.

참고: Spring Boot는 Hikari 관련 설정을 spring.datasource.hikari에 노출합니다.
이 예제는 여러 데이터소스 구현을 지원하지 않으므로 더 일반적인 configuration 하위 네임스페이스를 사용합니다.

자세한 내용은 Configure a DataSourceDataSourceAutoConfiguration 클래스를 참조하세요.

두 개의 DataSource 구성하기

추가 DataSource를 정의하려면 이전 섹션과 유사한 접근 방식을 사용할 수 있습니다.
주요 차이점은 DataSource @BeandefaultCandidate=false로 선언해야 한다는 것입니다.
이렇게 하면 자동 구성된 DataSource가 백오프하는 것을 방지합니다.

참고: Spring Framework 참조 문서에서 이 기능을 더 자세히 설명합니다.

추가 DataSource가 필요한 곳에 주입되도록 허용하려면 다음 예제와 같이 @Qualifier로도 어노테이션을 지정하세요:

Java:

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyAdditionalDataSourceConfiguration {

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    @ConfigurationProperties("app.datasource")
    public HikariDataSource secondDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

}

Kotlin:

import com.zaxxer.hikari.HikariDataSource

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.DataSourceBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyAdditionalDataSourceConfiguration {

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    @ConfigurationProperties("app.datasource")
    fun secondDataSource(): HikariDataSource {
        return DataSourceBuilder.create().type(HikariDataSource::class.java).build()
    }

}

추가 DataSource를 사용하려면 주입 지점에 동일한 @Qualifier로 어노테이션을 지정하세요.

자동 구성된 데이터 소스와 추가 데이터 소스는 다음과 같이 구성할 수 있습니다:

Properties:

spring.datasource.url=jdbc:mysql://localhost/first
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.configuration.maximum-pool-size=30
app.datasource.url=jdbc:mysql://localhost/second
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.max-total=30

YAML:

spring:
  datasource:
    url: "jdbc:mysql://localhost/first"
    username: "dbuser"
    password: "dbpass"
    configuration:
      maximum-pool-size: 30
app:
  datasource:
    url: "jdbc:mysql://localhost/second"
    username: "dbuser"
    password: "dbpass"
    max-total: 30

자동 구성된 DataSource의 더 고급 구현별 구성은 spring.datasource.configuration.* 속성을 통해 사용할 수 있습니다.
다음 예제와 같이 추가 DataSource에도 동일한 개념을 적용할 수 있습니다:

Java:

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCompleteAdditionalDataSourceConfiguration {

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    @ConfigurationProperties("app.datasource")
    public DataSourceProperties secondDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    @ConfigurationProperties("app.datasource.configuration")
    public HikariDataSource secondDataSource(
            @Qualifier("secondDataSourceProperties") DataSourceProperties secondDataSourceProperties) {
        return secondDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

}

Kotlin:

import com.zaxxer.hikari.HikariDataSource

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyCompleteAdditionalDataSourceConfiguration {

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    @ConfigurationProperties("app.datasource")
    fun secondDataSourceProperties(): DataSourceProperties {
        return DataSourceProperties()
    }

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    @ConfigurationProperties("app.datasource.configuration")
    fun secondDataSource(secondDataSourceProperties: DataSourceProperties): HikariDataSource {
        return secondDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
    }

}

앞의 예제는 Spring Boot가 자동 구성에서 사용하는 것과 동일한 로직으로 추가 데이터 소스를 구성합니다.
app.datasource.configuration.* 속성은 선택한 구현을 기반으로 고급 설정을 제공합니다.

단일 커스텀 DataSource 구성과 마찬가지로, DataSourceBuildertype(Class) 메서드를 사용하여 하나 또는 두 DataSource 빈의 타입을 커스터마이징할 수 있습니다.
지원되는 타입에 대한 자세한 내용은 Supported Connection Pools를 참조하세요.

Spring Data Repository 사용하기

Spring Data는 다양한 유형의 Repository 인터페이스 구현을 생성할 수 있습니다.
Spring Boot는 이러한 Repository 구현이 auto-configuration packages 중 하나에 포함되어 있는 한 이 모든 것을 처리합니다. 일반적으로 @SpringBootApplication 또는 @EnableAutoConfiguration으로 어노테이션이 지정된 메인 애플리케이션 클래스의 패키지(또는 하위 패키지)입니다.

많은 애플리케이션의 경우 클래스패스에 올바른 Spring Data 의존성을 추가하기만 하면 됩니다.
JPA용 spring-boot-starter-data-jpa, Mongodb용 spring-boot-starter-data-mongodb 및 지원되는 다양한 기술을 위한 다른 스타터가 있습니다.
시작하려면 @Entity 객체를 처리할 몇 가지 repository 인터페이스를 만드세요.

Spring Boot는 auto-configuration packages를 스캔하여 Repository 구현의 위치를 결정합니다.
더 세밀한 제어를 위해 Spring Data의 @Enable…Repositories 어노테이션을 사용하세요.

Spring Data에 대한 자세한 내용은 Spring Data 프로젝트 페이지를 참조하세요.

Spring 구성과 @Entity 정의 분리하기

Spring Boot는 auto-configuration packages를 스캔하여 @Entity 정의의 위치를 결정합니다.
더 세밀한 제어를 위해 다음 예제와 같이 @EntityScan 어노테이션을 사용하세요:

Java:

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.persistence.autoconfigure.EntityScan;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = City.class)
public class MyApplication {

    // ...

}

Kotlin:

import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.persistence.autoconfigure.EntityScan
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = [City::class])
class MyApplication {

    // ...

}

스캔된 @Entity 정의 필터링하기

ManagedClassNameFilter 빈을 사용하여 @Entity 정의를 필터링할 수 있습니다.
이는 사용 가능한 엔티티의 하위 집합만 고려해야 하는 테스트에서 유용할 수 있습니다.
다음 예제에서는 com.example.app.customer 패키지의 엔티티만 포함됩니다:

Java:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter;

@Configuration(proxyBeanMethods = false)
public class MyEntityScanConfiguration {

    @Bean
    public ManagedClassNameFilter entityScanFilter() {
        return (className) -> className.startsWith("com.example.app.customer.");
    }

}

Kotlin:

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter

@Configuration(proxyBeanMethods = false)
class MyEntityScanConfiguration {

    @Bean
    fun entityScanFilter() : ManagedClassNameFilter {
        return ManagedClassNameFilter { className ->
            className.startsWith("com.example.app.customer.")
        }
    }
}

JPA 속성 구성하기

Spring Data JPA는 이미 일부 벤더 독립적인 구성 옵션(예: SQL 로깅용)을 제공하며, Spring Boot는 이러한 옵션과 Hibernate용 몇 가지 추가 옵션을 외부 구성 속성으로 노출합니다.
일부는 컨텍스트에 따라 자동으로 감지되므로 설정할 필요가 없습니다.

spring.jpa.hibernate.ddl-auto는 런타임 조건에 따라 다른 기본값을 갖기 때문에 특별한 경우입니다.
임베디드 데이터베이스를 사용하고 스키마 관리자(예: Liquibase 또는 Flyway)가 DataSource를 처리하지 않는 경우 기본값은 create-drop입니다.
다른 모든 경우에는 기본값이 none입니다.

사용할 dialect는 JPA 제공자가 감지합니다.
직접 dialect를 설정하려면 spring.jpa.database-platform 속성을 설정하세요.

설정할 가장 일반적인 옵션은 다음 예제에 나와 있습니다:

Properties:

spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.show-sql=true

YAML:

spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: "com.example.MyPhysicalNamingStrategy"
    show-sql: true

또한 spring.jpa.properties.*의 모든 속성은 로컬 EntityManagerFactory가 생성될 때 일반 JPA 속성으로 전달됩니다(접두사가 제거됨).

spring.jpa.properties.* 아래에 정의된 이름이 JPA 제공자가 예상하는 이름과 정확히 일치하는지 확인해야 합니다.
Spring Boot는 이러한 항목에 대해 완화된 바인딩을 시도하지 않습니다.

예를 들어, Hibernate의 배치 크기를 구성하려면 spring.jpa.properties.hibernate.jdbc.batch_size를 사용해야 합니다.
batchSize 또는 batch-size와 같은 다른 형식을 사용하면 Hibernate는 설정을 적용하지 않습니다.

참고: Hibernate 속성에 고급 커스터마이징을 적용해야 하는 경우 EntityManagerFactory가 생성되기 전에 호출될 HibernatePropertiesCustomizer 빈을 등록하는 것을 고려하세요.
이는 자동 구성에 의해 적용되는 모든 것보다 우선합니다.

Hibernate Naming Strategy 구성하기

Hibernate는 두 가지 다른 naming strategy를 사용하여 객체 모델의 이름을 해당 데이터베이스 이름으로 매핑합니다.
physical 및 implicit 전략 구현의 정규화된 클래스 이름은 각각 spring.jpa.hibernate.naming.physical-strategyspring.jpa.hibernate.naming.implicit-strategy 속성을 설정하여 구성할 수 있습니다.
또는 ImplicitNamingStrategy 또는 PhysicalNamingStrategy 빈이 애플리케이션 컨텍스트에서 사용 가능한 경우 Hibernate가 자동으로 이를 사용하도록 구성됩니다.

기본적으로 Spring Boot는 physical naming strategy를 CamelCaseToUnderscoresNamingStrategy로 구성합니다.
이 전략을 사용하면 모든 점이 밑줄로 대체되고 카멜 케이스도 밑줄로 대체됩니다.
또한 기본적으로 모든 테이블 이름은 소문자로 생성됩니다.
예를 들어, TelephoneNumber 엔티티는 telephone_number 테이블에 매핑됩니다.
스키마에 대소문자 혼용 식별자가 필요한 경우 다음 예제와 같이 커스텀 CamelCaseToUnderscoresNamingStrategy 빈을 정의하세요:

Java:

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;

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

@Configuration(proxyBeanMethods = false)
public class MyHibernateConfiguration {

    @Bean
    public PhysicalNamingStrategySnakeCaseImpl caseSensitivePhysicalNamingStrategy() {
        return new PhysicalNamingStrategySnakeCaseImpl() {

            @Override
            public Identifier toPhysicalColumnName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
                return logicalName;
            }

        };
    }

}

Kotlin:

import org.hibernate.boot.model.naming.Identifier
import org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {

    @Bean
    fun caseSensitivePhysicalNamingStrategy(): PhysicalNamingStrategySnakeCaseImpl {
        return object : PhysicalNamingStrategySnakeCaseImpl() {
            override fun toPhysicalColumnName(logicalName: Identifier, jdbcEnvironment: JdbcEnvironment): Identifier {
                return logicalName
            }
        }
    }

}

대신 Hibernate의 기본값을 사용하려면 다음 속성을 설정하세요:

Properties:

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

YAML:

spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

또는 다음 빈을 구성할 수 있습니다:

Java:

import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;

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

@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {

    @Bean
    PhysicalNamingStrategyStandardImpl caseSensitivePhysicalNamingStrategy() {
        return new PhysicalNamingStrategyStandardImpl();
    }

}

Kotlin:

import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
internal class MyHibernateConfiguration {

    @Bean
    fun caseSensitivePhysicalNamingStrategy(): PhysicalNamingStrategyStandardImpl {
        return PhysicalNamingStrategyStandardImpl()
    }

}

자세한 내용은 HibernateJpaAutoConfigurationJpaBaseConfiguration를 참조하세요.

Hibernate Second-Level Caching 구성하기

Hibernate second-level cache는 다양한 캐시 제공자에 대해 구성할 수 있습니다.
Hibernate가 캐시 제공자를 다시 조회하도록 구성하는 대신, 가능할 때마다 컨텍스트에서 사용 가능한 캐시 제공자를 제공하는 것이 좋습니다.

JCache로 이 작업을 수행하려면 먼저 org.hibernate.orm:hibernate-jcache가 클래스패스에 있는지 확인하세요.
그런 다음 다음 예제와 같이 HibernatePropertiesCustomizer 빈을 추가하세요:

Java:

import org.hibernate.cache.jcache.ConfigSettings;

import org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyHibernateSecondLevelCacheConfiguration {

    @Bean
    public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {
        return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
    }

}

Kotlin:

import org.hibernate.cache.jcache.ConfigSettings
import org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer
import org.springframework.cache.jcache.JCacheCacheManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyHibernateSecondLevelCacheConfiguration {

    @Bean
    fun hibernateSecondLevelCacheCustomizer(cacheManager: JCacheCacheManager): HibernatePropertiesCustomizer {
        return HibernatePropertiesCustomizer { properties ->
            val cacheManager = cacheManager.cacheManager
            if (cacheManager != null) {
                properties[ConfigSettings.CACHE_MANAGER] = cacheManager
            }
        }
    }

}

이 커스터마이저는 애플리케이션이 사용하는 것과 동일한 CacheManager를 사용하도록 Hibernate를 구성합니다.
별도의 CacheManager 인스턴스를 사용하는 것도 가능합니다.
자세한 내용은 Hibernate 사용자 가이드를 참조하세요.

Hibernate 컴포넌트에서 의존성 주입 사용하기

기본적으로 Spring Boot는 BeanFactory를 사용하는 BeanContainer 구현을 등록하여 컨버터와 엔티티 리스너가 일반 의존성 주입을 사용할 수 있도록 합니다.

hibernate.resource.beans.container 속성을 제거하거나 변경하는 HibernatePropertiesCustomizer를 등록하여 이 동작을 비활성화하거나 조정할 수 있습니다.

커스텀 EntityManagerFactory 사용하기

EntityManagerFactory의 구성을 완전히 제어하려면 'entityManagerFactory'라는 이름의 @Bean을 추가해야 합니다.
Spring Boot 자동 구성은 해당 타입의 빈이 있는 경우 엔티티 매니저를 끕니다.

참고: LocalContainerEntityManagerFactoryBean에 대한 빈을 직접 생성하면 자동 구성된 LocalContainerEntityManagerFactoryBean을 생성하는 동안 적용된 모든 커스터마이징이 손실됩니다.
JPA 및 벤더 속성을 유지하려면 자동 구성된 EntityManagerFactoryBuilder를 사용해야 합니다.
이는 naming strategy 또는 DDL 모드와 같은 것을 구성하기 위해 spring.jpa.* 속성에 의존하는 경우 특히 중요합니다.

여러 EntityManagerFactory 사용하기

여러 데이터소스에 대해 JPA를 사용해야 하는 경우 데이터소스당 하나의 EntityManagerFactory가 필요할 수 있습니다.
Spring ORM의 LocalContainerEntityManagerFactoryBean을 사용하면 필요에 맞게 EntityManagerFactory를 구성할 수 있습니다.
두 번째 EntityManagerFactory에 대한 설정을 바인딩하기 위해 JpaProperties를 재사용할 수도 있습니다.
두 번째 DataSource 구성 예제를 기반으로 다음 예제와 같이 두 번째 EntityManagerFactory를 정의할 수 있습니다:

Java:

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.jpa.autoconfigure.JpaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

@Configuration(proxyBeanMethods = false)
public class MyAdditionalEntityManagerFactoryConfiguration {

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    @ConfigurationProperties("app.jpa")
    public JpaProperties secondJpaProperties() {
        return new JpaProperties();
    }

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory(@Qualifier("second") DataSource dataSource,
            @Qualifier("second") JpaProperties jpaProperties) {
        EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(jpaProperties);
        return builder.dataSource(dataSource).packages(Order.class).persistenceUnit("second").build();
    }

    private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
        JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
        Function<DataSource, Map<String, ?>> jpaPropertiesFactory = (dataSource) -> createJpaProperties(dataSource,
                jpaProperties.getProperties());
        return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaPropertiesFactory, null);
    }

    private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {
        // ... map JPA properties as needed
        return new HibernateJpaVendorAdapter();
    }

    private Map<String, ?> createJpaProperties(DataSource dataSource, Map<String, ?> existingProperties) {
        Map<String, ?> jpaProperties = new LinkedHashMap<>(existingProperties);
        // ... map JPA properties that require the DataSource (e.g. DDL flags)
        return jpaProperties;
    }

}

Kotlin:

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jpa.EntityManagerFactoryBuilder
import org.springframework.boot.jpa.autoconfigure.JpaProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.orm.jpa.JpaVendorAdapter
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
import javax.sql.DataSource

@Configuration(proxyBeanMethods = false)
class MyAdditionalEntityManagerFactoryConfiguration {

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    @ConfigurationProperties("app.jpa")
    fun secondJpaProperties(): JpaProperties {
        return JpaProperties()
    }

    @Qualifier("second")
    @Bean(defaultCandidate = false)
    fun firstEntityManagerFactory(
        @Qualifier("second") dataSource: DataSource,
        @Qualifier("second") jpaProperties: JpaProperties
    ): LocalContainerEntityManagerFactoryBean {
        val builder = createEntityManagerFactoryBuilder(jpaProperties)
        return builder.dataSource(dataSource).packages(Order::class.java).persistenceUnit("second").build()
    }

    private fun createEntityManagerFactoryBuilder(jpaProperties: JpaProperties): EntityManagerFactoryBuilder {
        val jpaVendorAdapter = createJpaVendorAdapter(jpaProperties)
        val jpaPropertiesFactory = { dataSource: DataSource ->
                createJpaProperties(dataSource, jpaProperties.properties) }
        return EntityManagerFactoryBuilder(jpaVendorAdapter, jpaPropertiesFactory, null)
    }

    private fun createJpaVendorAdapter(jpaProperties: JpaProperties): JpaVendorAdapter {
        // ... map JPA properties as needed
        return HibernateJpaVendorAdapter()
    }

    private fun createJpaProperties(dataSource: DataSource, existingProperties: Map<String, *>): Map<String, *> {
        val jpaProperties: Map<String, *> = LinkedHashMap(existingProperties)
        // ... map JPA properties that require the DataSource (e.g. DDL flags)
        return jpaProperties
    }

}

위 예제는 @Qualifier("second")로 한정된 DataSource 빈을 사용하여 EntityManagerFactory를 생성합니다.
Order와 동일한 패키지에 있는 엔티티를 스캔합니다.
app.jpa 네임스페이스를 사용하여 추가 JPA 속성을 매핑할 수 있습니다.
@Bean(defaultCandidate=false)를 사용하면 secondJpaPropertiessecondEntityManagerFactory 빈이 동일한 타입의 자동 구성된 빈과 간섭하지 않고 정의될 수 있습니다.

참고: Spring Framework 참조 문서에서 이 기능을 더 자세히 설명합니다.

JPA 액세스가 필요한 다른 추가 데이터 소스에 대해서도 유사한 구성을 제공해야 합니다.
작업을 완료하려면 각 EntityManagerFactory에 대해 JpaTransactionManager도 구성해야 합니다.
또는 두 가지를 모두 포괄하는 JTA 트랜잭션 매니저를 사용할 수 있습니다.

Spring Data를 사용하는 경우 다음 예제와 같이 @EnableJpaRepositories를 적절히 구성해야 합니다:

Java:

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Order.class, entityManagerFactoryRef = "entityManagerFactory")
public class OrderConfiguration {

}

Kotlin:

import org.springframework.context.annotation.Configuration
import org.springframework.data.jpa.repository.config.EnableJpaRepositories

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = [Order::class], entityManagerFactoryRef = "firstEntityManagerFactory")
class OrderConfiguration

Java:

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Customer.class, entityManagerFactoryRef = "secondEntityManagerFactory")
public class CustomerConfiguration {

}

Kotlin:

import org.springframework.context.annotation.Configuration
import org.springframework.data.jpa.repository.config.EnableJpaRepositories

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = [Customer::class], entityManagerFactoryRef = "secondEntityManagerFactory")
class CustomerConfiguration

전통적인 persistence.xml 파일 사용하기

Spring Boot는 기본적으로 META-INF/persistence.xml을 검색하거나 사용하지 않습니다.
전통적인 persistence.xml을 사용하려면 LocalEntityManagerFactoryBean 타입의 자체 @Bean을 정의하고(ID는 'entityManagerFactory') 거기에서 persistence unit 이름을 설정해야 합니다.

기본 설정은 JpaBaseConfiguration을 참조하세요.

Spring Data JPA 및 Mongo Repository 사용하기

Spring Data JPA와 Spring Data Mongo는 모두 Repository 구현을 자동으로 생성할 수 있습니다.
둘 다 클래스패스에 있는 경우 Spring Boot에 어떤 리포지토리를 생성할지 알려주기 위해 몇 가지 추가 구성을 수행해야 할 수 있습니다.
이를 수행하는 가장 명시적인 방법은 표준 Spring Data @EnableJpaRepositories@EnableMongoRepositories 어노테이션을 사용하고 Repository 인터페이스의 위치를 제공하는 것입니다.

외부 구성에서 자동 구성된 리포지토리를 켜고 끌 수 있는 플래그(spring.data.*.repositories.enabledspring.data.*.repositories.type)도 있습니다.
예를 들어, Mongo 리포지토리를 끄고 자동 구성된 MongoTemplate을 계속 사용하려는 경우 유용합니다.

다른 자동 구성된 Spring Data 리포지토리 타입(Elasticsearch, Redis 등)에도 동일한 장애물과 기능이 존재합니다.
이들을 사용하려면 어노테이션과 플래그의 이름을 적절히 변경하세요.

Spring Data의 웹 지원 커스터마이징하기

Spring Data는 웹 애플리케이션에서 Spring Data 리포지토리 사용을 단순화하는 웹 지원을 제공합니다.
Spring Boot는 spring.data.web 네임스페이스에서 구성을 커스터마이징하기 위한 속성을 제공합니다.
Spring Data REST를 사용하는 경우 대신 spring.data.rest 네임스페이스의 속성을 사용해야 합니다.

Spring Data Repository를 REST 엔드포인트로 노출하기

Spring Data REST는 애플리케이션에 대해 Spring MVC가 활성화된 경우 Repository 구현을 REST 엔드포인트로 노출할 수 있습니다.

Spring Boot는 RepositoryRestConfiguration을 커스터마이징하는 유용한 속성 세트(spring.data.rest 네임스페이스에서)를 노출합니다.
추가 커스터마이징을 제공해야 하는 경우 RepositoryRestConfigurer 빈을 사용해야 합니다.

참고: 커스텀 RepositoryRestConfigurer에 순서를 지정하지 않으면 Spring Boot가 내부적으로 사용하는 것보다 나중에 실행됩니다.
순서를 지정해야 하는 경우 0보다 큰지 확인하세요.

JPA가 사용하는 컴포넌트 구성하기

JPA가 사용하는 컴포넌트를 구성하려면 JPA보다 먼저 컴포넌트를 초기화해야 합니다.
컴포넌트가 자동 구성되면 Spring Boot가 이를 처리합니다.
예를 들어, Flyway가 자동 구성되면 Hibernate는 Flyway에 의존하도록 구성되어 Hibernate가 데이터베이스를 사용하기 전에 Flyway가 데이터베이스를 초기화할 기회를 갖습니다.

컴포넌트를 직접 구성하는 경우 EntityManagerFactoryDependsOnPostProcessor 하위 클래스를 필요한 의존성을 설정하는 편리한 방법으로 사용할 수 있습니다.
예를 들어, Hibernate Search를 인덱스 관리자로 Elasticsearch와 함께 사용하는 경우 다음 예제와 같이 모든 EntityManagerFactory 빈이 elasticsearchClient 빈에 의존하도록 구성해야 합니다:

Java:

import jakarta.persistence.EntityManagerFactory;

import org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor;
import org.springframework.stereotype.Component;

/**
 * {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
 * {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
 */
@Component
public class ElasticsearchEntityManagerFactoryDependsOnPostProcessor
        extends EntityManagerFactoryDependsOnPostProcessor {

    public ElasticsearchEntityManagerFactoryDependsOnPostProcessor() {
        super("elasticsearchClient");
    }

}

Kotlin:

import org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor
import org.springframework.stereotype.Component

@Component
class ElasticsearchEntityManagerFactoryDependsOnPostProcessor :
    EntityManagerFactoryDependsOnPostProcessor("elasticsearchClient")

두 개의 DataSource로 jOOQ 구성하기

여러 데이터 소스와 함께 jOOQ를 사용해야 하는 경우 각각에 대해 자체 DSLContext를 생성해야 합니다.
자세한 내용은 JooqAutoConfiguration을 참조하세요.

참고: 특히 ExceptionTranslatorExecuteListenerSpringTransactionProvider는 단일 DataSource로 자동 구성이 수행하는 것과 유사한 기능을 제공하기 위해 재사용할 수 있습니다.


출처: https://docs.spring.io/spring-boot/4.0-SNAPSHOT/how-to/data-access.html

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유