이 버전은 아직 개발 중이며 안정적이지 않습니다. 최신 안정 버전은 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
의 타입을 지정하고 메서드의 반환 타입을 업데이트하세요.
예를 들어, 다음은 DataSourceBuilder
로 HikariDataSource
를 생성하는 방법을 보여줍니다:
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.*
속성으로 노출된다는 점이 다릅니다.DataSourceProperties
는 url
에서 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 DataSource와 DataSourceAutoConfiguration
클래스를 참조하세요.
두 개의 DataSource 구성하기
추가 DataSource
를 정의하려면 이전 섹션과 유사한 접근 방식을 사용할 수 있습니다.
주요 차이점은 DataSource
@Bean
을 defaultCandidate=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
구성과 마찬가지로, DataSourceBuilder
의 type(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-strategy
및 spring.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()
}
}
자세한 내용은 HibernateJpaAutoConfiguration
및 JpaBaseConfiguration
를 참조하세요.
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)
를 사용하면 secondJpaProperties
및 secondEntityManagerFactory
빈이 동일한 타입의 자동 구성된 빈과 간섭하지 않고 정의될 수 있습니다.
참고: 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.enabled
및 spring.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
을 참조하세요.
참고: 특히
ExceptionTranslatorExecuteListener
및SpringTransactionProvider
는 단일DataSource
로 자동 구성이 수행하는 것과 유사한 기능을 제공하기 위해 재사용할 수 있습니다.
출처: https://docs.spring.io/spring-boot/4.0-SNAPSHOT/how-to/data-access.html