データアクセス

Spring Boot には、データソースを操作するためのスタータが多数含まれています。このセクションでは、その方法に関する質問に回答します。

カスタム DataSource を構成する

独自の DataSource を設定するには、設定でその型の @Bean を定義します。Spring Boot は、データベースの初期化を含め、DataSource が必要な場所で再利用します。一部の設定を外部化する必要がある場合は、DataSource を環境にバインドできます( "サードパーティの構成" を参照)。

次の例は、Bean でデータソースを定義する方法を示しています。

  • Java

  • Kotlin

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(prefix = "app.datasource")
	public SomeDataSource dataSource() {
		return new SomeDataSource();
	}

}
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(prefix = "app.datasource")
	fun dataSource(): SomeDataSource {
		return SomeDataSource()
	}

}

次の例は、プロパティを設定してデータソースを定義する方法を示しています。

  • プロパティ

  • YAML

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

SomeDataSource に URL、ユーザー名、プールサイズの通常の JavaBean プロパティがあるとすると、これらの設定は、DataSource が他のコンポーネントで使用可能になる前に自動的にバインドされます。

Spring Boot は、標準データソースの 1 つ (クラスパス上にある場合) を作成するために使用できる、DataSourceBuilder というユーティリティビルダークラスも提供します。ビルダーは、クラスパスで使用可能なものに基づいて、使用するデータソースを検出できます。また、JDBC URL に基づいてドライバーを自動検出します。

次の例は、DataSourceBuilder を使用してデータソースを作成する方法を示しています。

  • Java

  • 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)
public class MyDataSourceConfiguration {

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

}
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 データソースを定義する方法を示しています。

  • プロパティ

  • YAML

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

しかし、落とし穴があります。接続プールの実際の種類が公開されていないため、カスタム DataSource のメタデータにキーが生成されず、(DataSource インターフェースはプロパティを公開しないため) IDE で補完機能を使用できません。また、クラスパスに Hikari がある場合、Hikari には url プロパティがない (ただし、jdbcUrl プロパティはある) ため、この基本セットアップは機能しません。その場合は、設定を次のように書き直す必要があります。

  • プロパティ

  • YAML

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

接続プールが DataSource ではなく専用の実装を使用して返すように強制することで、これを修正できます。実行時に実装を変更することはできませんが、オプションのリストは明示的になります。

次の例は、DataSourceBuilder を使用して HikariDataSource を作成する方法を示しています。

  • Java

  • 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)
public class MyDataSourceConfiguration {

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

}
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()
	}

}

DataSourceProperties の機能を活用することで、さらに先に進むこともできます。つまり、URL が提供されていない場合は、デフォルトの組み込みデータベースに適切なユーザー名とパスワードを提供します。任意の DataSourceProperties オブジェクトの状態から DataSourceBuilder を簡単に初期化できるため、Spring Boot が自動的に作成する DataSource を挿入することもできます。ただし、これにより、構成が 2 つの名前空間に分割されます。spring.datasource 上の urlusernamepasswordtypedriver と、残りはカスタム名前空間(app.datasource)です。これを回避するには、次の例に示すように、カスタム名前空間でカスタム DataSourceProperties を再定義できます。

  • Java

  • Kotlin

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
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();
	}

}
import com.zaxxer.hikari.HikariDataSource
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
import org.springframework.boot.context.properties.ConfigurationProperties
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()
	}

}

この設定により、専用の接続プールが(コードで)選択され、その設定が app.datasource.configuration サブ名前空間で公開されることを除いて、デフォルトで Spring Boot が行うことと同期します。DataSourceProperties が url/jdbcUrl 変換を処理するため、次のように構成できます。

  • プロパティ

  • YAML

app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
app:
  datasource:
    url: "jdbc:mysql://localhost/test"
    username: "dbuser"
    password: "dbpass"
    configuration:
      maximum-pool-size: 30
Spring Boot は、Hikari 固有の設定を spring.datasource.hikari に公開します。この例では複数のデータソース実装をサポートしていないため、この例ではより一般的な configuration サブ名前空間を使用します。
カスタム構成では Hikari を選択するため、app.datasource.type は効果がありません。実際には、ビルダーはそこに設定する可能性のある値で初期化され、.type() の呼び出しによってオーバーライドされます。

詳細については、「Spring Boot 機能」セクションの "DataSource を構成する" および DataSourceAutoConfiguration [GitHub] (英語) クラスを参照してください。

2 つの DataSources を構成する

複数のデータソースを構成する必要がある場合は、前のセクションで説明したのと同じトリックを適用できます。ただし、今後のさまざまな自動構成で型別に 1 つを取得できることが想定されるため、DataSource インスタンスの 1 つを @Primary としてマークする必要があります。

独自の DataSource を作成すると、自動構成はバックオフします。次の例では、自動構成がプライマリデータソースで提供するものとまったく同じ機能セットを提供します。

  • Java

  • Kotlin

import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;

import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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;
import org.springframework.context.annotation.Primary;

@Configuration(proxyBeanMethods = false)
public class MyDataSourcesConfiguration {

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

	@Bean
	@Primary
	@ConfigurationProperties("app.datasource.first.configuration")
	public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) {
		return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
	}

	@Bean
	@ConfigurationProperties("app.datasource.second")
	public BasicDataSource secondDataSource() {
		return DataSourceBuilder.create().type(BasicDataSource.class).build();
	}

}
import com.zaxxer.hikari.HikariDataSource
import org.apache.commons.dbcp2.BasicDataSource
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
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
import org.springframework.context.annotation.Primary

@Configuration(proxyBeanMethods = false)
class MyDataSourcesConfiguration {

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

	@Bean
	@Primary
	@ConfigurationProperties("app.datasource.first.configuration")
	fun firstDataSource(firstDataSourceProperties: DataSourceProperties): HikariDataSource {
		return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
	}

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

}
データベース初期化機能がコピーを使用するように、firstDataSourceProperties に @Primary のフラグを立てる必要があります(初期化を使用する場合)。

両方のデータソースは、高度なカスタマイズにも対応しています。たとえば、次のように構成できます。

  • プロパティ

  • YAML

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

    second:
      url: "jdbc:mysql://localhost/second"
      username: "dbuser"
      password: "dbpass"
      max-total: 30

次の例に示すように、セカンダリ DataSource にも同じ概念を適用できます。

  • Java

  • Kotlin

import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;

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

@Configuration(proxyBeanMethods = false)
public class MyCompleteDataSourcesConfiguration {

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

	@Bean
	@Primary
	@ConfigurationProperties("app.datasource.first.configuration")
	public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) {
		return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
	}

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

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

}
import com.zaxxer.hikari.HikariDataSource
import org.apache.commons.dbcp2.BasicDataSource
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary

@Configuration(proxyBeanMethods = false)
class MyCompleteDataSourcesConfiguration {

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

	@Bean
	@Primary
	@ConfigurationProperties("app.datasource.first.configuration")
	fun firstDataSource(firstDataSourceProperties: DataSourceProperties): HikariDataSource {
		return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
	}

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

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

}

前の例では、Spring Boot が自動構成で使用するのと同じロジックを使用して、カスタム名前空間に 2 つのデータソースを構成します。各 configuration サブ名前空間は、選択した実装に基づいて高度な設定を提供することに注意してください。

Spring Data リポジトリを使用する

Spring Data は、さまざまな種類の @Repository インターフェースの実装を作成できます。Spring Boot は、これらの @Repository アノテーションがいずれかの自動構成パッケージ (通常は @SpringBootApplication または @EnableAutoConfiguration アノテーションが付けられたメインアプリケーションクラスのパッケージ (またはサブパッケージ)) に含まれている限り、これらすべてを処理します。

多くのアプリケーションでは、クラスパスに適切な Spring Data 依存関係を設定するだけで済みます。JPA 用の spring-boot-starter-data-jpa、Mongodb 用の spring-boot-starter-data-mongodb、サポートされているテクノロジー用の他のさまざまなスターターがあります。開始するには、@Entity オブジェクトを処理するためのリポジトリインターフェースをいくつか作成します。

Spring Boot は、自動構成パッケージをスキャンして、@Repository 定義の場所を特定します。さらに制御するには、Spring Data の @Enable … Repositories アノテーションを使用します。

Spring Data の詳細については、Spring Data プロジェクトページを参照してください。

Spring 構成から @Entity 定義を分離する

Spring Boot は、自動構成パッケージをスキャンして、@Entity 定義の場所を特定します。さらに制御するには、次の例に示すように、@EntityScan アノテーションを使用します。

  • Java

  • Kotlin

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

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

	// ...

}
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.context.annotation.Configuration

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

	// ...

}

スキャンされた @Entity 定義をフィルターする

ManagedClassNameFilter Bean を使用して @Entity 定義をフィルターすることができます。これは、使用可能なエンティティのサブセットのみを考慮する必要があるテストで役立ちます。次の例では、com.example.app.customer パッケージのエンティティのみが含まれます。

  • Java

  • Kotlin

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");
	}

}
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 です。

使用するダイアレクトは JPA プロバイダーによって検出されます。ダイアレクトを自分で設定する場合は、spring.jpa.database-platform プロパティを設定します。

設定する最も一般的なオプションを次の例に示します。

  • プロパティ

  • YAML

spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.show-sql=true
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 Bean を登録することを検討してください。これは、自動構成によって適用されるものよりも優先されます。

Hibernate 命名戦略の構成

Hibernate は、2 つの異なる命名戦略 (英語) を使用して、オブジェクトモデルから対応するデータベース名に名前をマッピングします。spring.jpa.hibernate.naming.physical-strategy プロパティと spring.jpa.hibernate.naming.implicit-strategy プロパティをそれぞれ設定することにより、物理的および暗黙的な戦略実装の完全修飾クラス名を構成できます。または、ImplicitNamingStrategy または PhysicalNamingStrategy Bean がアプリケーションコンテキストで使用可能な場合、Hibernate はそれらを使用するように自動的に構成されます。

デフォルトでは、Spring Boot は CamelCaseToUnderscoresNamingStrategy を使用して物理的な命名戦略を構成します。この戦略を使用すると、すべてのドットがアンダースコアに置き換えられ、キャメルケースもアンダースコアに置き換えられます。さらに、デフォルトでは、すべてのテーブル名は小文字で生成されます。例: TelephoneNumber エンティティは telephone_number テーブルにマップされます。スキーマで大文字と小文字が混在する識別子が必要な場合は、次の例に示すように、カスタム CamelCaseToUnderscoresNamingStrategy Bean を定義します。

  • Java

  • Kotlin

import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy;
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 CamelCaseToUnderscoresNamingStrategy caseSensitivePhysicalNamingStrategy() {
		return new CamelCaseToUnderscoresNamingStrategy() {

			@Override
			protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
				return false;
			}

		};
	}

}
import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy
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(): CamelCaseToUnderscoresNamingStrategy {
		return object : CamelCaseToUnderscoresNamingStrategy() {
			override fun isCaseInsensitive(jdbcEnvironment: JdbcEnvironment): Boolean {
				return false
			}
		}
	}

}

代わりに Hibernate のデフォルトを使用する場合は、次のプロパティを設定します。

  • プロパティ

  • YAML

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

または、次の Bean を構成できます。

  • Java

  • Kotlin

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();
	}

}
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 [GitHub] (英語) および JpaBaseConfiguration [GitHub] (英語) を参照してください。

Hibernate 2 次キャッシュを構成する

Hibernate 2 次キャッシュ (英語) は、さまざまなキャッシュプロバイダーに対して構成できます。キャッシュプロバイダーを再度検索するように Hibernate を構成するのではなく、可能な場合はコンテキストで利用可能なものを提供することをお勧めします。

JCache でこれを行うには、まず org.hibernate.orm:hibernate-jcache がクラスパスで使用可能であることを確認します。次に、次の例に示すように、HibernatePropertiesCustomizer Bean を追加します。

  • Java

  • Kotlin

import org.hibernate.cache.jcache.ConfigSettings;

import org.springframework.boot.autoconfigure.orm.jpa.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());
	}

}
import org.hibernate.cache.jcache.ConfigSettings
import org.springframework.boot.autoconfigure.orm.jpa.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 ->
			properties[ConfigSettings.CACHE_MANAGER] = cacheManager.cacheManager
		}
	}

}

このカスタマイザーは、アプリケーションが使用するものと同じ CacheManager を使用するように Hibernate を構成します。個別の CacheManager インスタンスを使用することもできます。詳細については、Hibernate ユーザーガイド (英語) を参照してください。

Hibernate コンポーネントでの依存性注入の使用

デフォルトでは、Spring Boot は BeanFactory を使用する BeanContainer 実装を登録して、コンバーターとエンティティリスナーが通常の依存性注入を使用できるようにします。

hibernate.resource.beans.container プロパティを削除または変更する HibernatePropertiesCustomizer を登録することにより、この動作を無効化または調整できます。

カスタム EntityManagerFactory を使用する

EntityManagerFactory の構成を完全に制御するには、"entityManagerFactory" という名前の @Bean を追加する必要があります。Spring Boot 自動構成は、その型の Bean が存在する場合、エンティティマネージャーをオフにします。

複数の EntityManagerFactories を使用する

複数のデータソースに対して JPA を使用する必要がある場合は、データソースごとに 1 つの EntityManagerFactory が必要になる可能性があります。Spring ORM の LocalContainerEntityManagerFactoryBean を使用すると、ニーズに合わせて EntityManagerFactory を構成できます。次の例に示すように、JpaProperties を再利用して、各 EntityManagerFactory の設定をバインドすることもできます。

  • Java

  • Kotlin

import javax.sql.DataSource;

import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
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 MyEntityManagerFactoryConfiguration {

	@Bean
	@ConfigurationProperties("app.jpa.first")
	public JpaProperties firstJpaProperties() {
		return new JpaProperties();
	}

	@Bean
	public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(DataSource firstDataSource,
			JpaProperties firstJpaProperties) {
		EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(firstJpaProperties);
		return builder.dataSource(firstDataSource).packages(Order.class).persistenceUnit("firstDs").build();
	}

	private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
		JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
		return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), null);
	}

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

}
import javax.sql.DataSource

import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder
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)
class MyEntityManagerFactoryConfiguration {

	@Bean
	@ConfigurationProperties("app.jpa.first")
	fun firstJpaProperties(): JpaProperties {
		return JpaProperties()
	}

	@Bean
	fun firstEntityManagerFactory(
		firstDataSource: DataSource?,
		firstJpaProperties: JpaProperties
	): LocalContainerEntityManagerFactoryBean {
		val builder = createEntityManagerFactoryBuilder(firstJpaProperties)
		return builder.dataSource(firstDataSource).packages(Order::class.java).persistenceUnit("firstDs").build()
	}

	private fun createEntityManagerFactoryBuilder(jpaProperties: JpaProperties): EntityManagerFactoryBuilder {
		val jpaVendorAdapter = createJpaVendorAdapter(jpaProperties)
		return EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.properties, null)
	}

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

}

上記の例では、firstDataSource という名前の DataSource Bean を使用して EntityManagerFactory を作成します。Order と同じパッケージにあるエンティティをスキャンします。app.first.jpa 名前空間を使用して、追加の JPA プロパティをマップすることができます。

LocalContainerEntityManagerFactoryBean の Bean を自分で作成すると、自動構成された LocalContainerEntityManagerFactoryBean の作成中に適用されたカスタマイズはすべて失われます。例: Hibernate の場合、spring.jpa.hibernate プレフィックスのプロパティは LocalContainerEntityManagerFactoryBean に自動的に適用されません。命名戦略や DDL モードなどの構成にこれらのプロパティに依存していた場合は、LocalContainerEntityManagerFactoryBean Bean を作成するときに明示的に構成する必要があります。

JPA アクセスが必要な追加のデータソースについても、同様の構成を提供する必要があります。全体像を完成させるには、EntityManagerFactory ごとに JpaTransactionManager も構成する必要があります。または、両方にまたがる JTA トランザクションマネージャーを使用できる場合もあります。

Spring Data を使用する場合は、次の例に示すように、それに応じて @EnableJpaRepositories を構成する必要があります。

  • Java

  • Kotlin

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

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

}
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

  • Kotlin

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 {

}
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 ( "entityManagerFactory" の ID を使用)を定義し、そこに永続性ユニット名を設定する必要があります。

デフォルト設定については、JpaBaseConfiguration [GitHub] (英語) を参照してください。

Spring Data JPA および Mongo リポジトリを使用する

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 の Web サポートのカスタマイズ

Spring Data は、Web アプリケーションでの Spring Data リポジトリの使用を簡素化する Web サポートを提供します。Spring Boot は、その構成をカスタマイズするための spring.data.web 名前空間のプロパティを提供します。Spring Data REST を使用している場合は、代わりに spring.data.rest 名前空間のプロパティを使用する必要があることに注意してください。

Spring Data リポジトリを REST エンドポイントとして公開する

アプリケーションで Spring MVC が有効になっている場合、Spring Data REST は Repository 実装を REST エンドポイントとして公開できます。

Spring Boot は、RepositoryRestConfiguration (Javadoc) をカスタマイズする一連の有用なプロパティ(spring.data.rest 名前空間から)を公開します。追加のカスタマイズを提供する必要がある場合は、RepositoryRestConfigurer (Javadoc) Bean を使用する必要があります。

カスタム RepositoryRestConfigurer で順序を指定しない場合、Spring Boot が内部的に使用した後に実行されます。順序を指定する必要がある場合は、0 より大きいことを確認してください。

JPA によって使用されるコンポーネントを構成する

JPA が使用するコンポーネントを構成する場合は、JPA の前にコンポーネントが初期化されていることを確認する必要があります。コンポーネントが自動構成されると、Spring Boot がこれを処理します。例: Flyway が自動構成されると、Hibernate は Flyway に依存するように構成されるため、Hibernate がデータベースを使用する前に Flyway がデータベースを初期化する機会が得られます。

コンポーネントを自分で構成する場合は、EntityManagerFactoryDependsOnPostProcessor サブクラスを使用して、必要な依存関係をセットアップする便利な方法として使用できます。例: インデックスマネージャーとして Elasticsearch で Hibernate Search を使用する場合、次の例に示すように、EntityManagerFactory Bean は elasticsearchClient Bean に依存するように構成する必要があります。

  • Java

  • Kotlin

import jakarta.persistence.EntityManagerFactory;

import org.springframework.boot.autoconfigure.orm.jpa.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");
	}

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

@Component
class ElasticsearchEntityManagerFactoryDependsOnPostProcessor :
	EntityManagerFactoryDependsOnPostProcessor("elasticsearchClient")

2 つの DataSources で jOOQ を構成する

複数のデータソースで jOOQ を使用する必要がある場合は、それぞれに独自の DSLContext を作成する必要があります。詳細については、JooqAutoConfiguration [GitHub] (英語) を参照してください。

特に、JooqExceptionTranslator および SpringTransactionProvider を再利用して、単一の DataSource で自動構成が行うことと同様の機能を提供できます。