Master Custom Data Sources and JPA Configuration in Spring Boot
This guide walks through configuring custom and multiple data sources, using Spring Data repositories, fine‑tuning JPA and Hibernate settings, customizing naming strategies, enabling second‑level caching, and exposing repositories as REST endpoints in a Spring Boot 2.4.13 application.
Environment: Spring Boot 2.4.13
Custom DataSource Configuration
<code>@Bean
@ConfigurationProperties(prefix="app.datasource")
public DataSource dataSource() {
return new FancyDataSource();
}
</code>Corresponding YAML configuration:
<code>app:
datasource:
url: "jdbc:h2:mem:mydb"
username: "sa"
password: "123123"
pool-size: 30
</code>The FancyDataSource class provides url , username , and pool-size properties.
Using DataSourceBuilder
<code>@Bean
@ConfigurationProperties("app.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
</code>Be aware of a trap: if the actual pool type is not supplied, no metadata keys are generated and IDE completion may be missing. When HikariCP is on the classpath, the basic setup fails because Hikari uses jdbcUrl instead of url . In that case use:
<code>app:
datasource:
jdbc-url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
</code>Force a Specific DataSource Type
<code>@Bean
@ConfigurationProperties("app.datasource")
public HikariDataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
</code>Multiple DataSource Configuration
When configuring more than one data source, mark one as @Primary so that auto‑configuration can locate a default.
<code>@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource() {
return firstDataSourceProperties()
.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
</code>YAML example for the two data sources:
<code>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
</code>Using Spring Data Repositories
Spring Data can generate implementations for @Repository interfaces automatically when they reside in the same package (or sub‑package) as the @EnableAutoConfiguration class. Add the appropriate starter, e.g., spring-boot-starter-data-jpa or spring-boot-starter-data-mongodb , and create repository interfaces for your @Entity classes.
Separate @Entity Scanning from Spring Configuration
<code>@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = City.class)
public class Application {
// ...
}
</code>Configure JPA Properties
Spring Data JPA exposes vendor‑independent options such as SQL logging. The spring.jpa.hibernate.ddl-auto property defaults to create-drop for embedded databases without a schema manager, otherwise to none . To set a specific dialect, use spring.jpa.database-platform .
<code>spring:
jpa:
hibernate:
naming:
physical-strategy: "com.example.MyPhysicalNamingStrategy"
show-sql: true
</code>Hibernate Naming Strategy
Hibernate maps object names to database identifiers using physical and implicit strategies. The default in Spring Boot is SpringPhysicalNamingStrategy , which converts camel case to snake case and lower‑cases table names. To use a case‑sensitive strategy, define a bean:
<code>@Bean
public SpringPhysicalNamingStrategy caseSensitivePhysicalNamingStrategy() {
return new SpringPhysicalNamingStrategy() {
@Override
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return false;
}
};
}
</code>Alternatively, switch to Hibernate’s standard implementation:
<code>spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
</code>Hibernate Second‑Level Cache
To enable a second‑level cache with JCache, ensure org.hibernate.HibernateJCache is on the classpath and provide a HibernatePropertiesCustomizer bean:
<code>@Configuration(proxyBeanMethods = false)
public class HibernateSecondLevelCacheExample {
@Bean
public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {
return properties -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
}
}
</code>Multiple EntityManagerFactories
When several data sources require separate JPA contexts, define a distinct EntityManagerFactory for each. Use LocalContainerEntityManagerFactoryBean and share common JPA properties:
<code>@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();
}
</code>Expose Spring Data Repositories as REST Endpoints
Include the Spring Data REST starter to automatically publish repository interfaces as RESTful services (requires Spring MVC):
<code><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
</dependency>
</code>With these configurations, you can fully customize data source handling, JPA/Hibernate behavior, caching, and expose data access layers as REST APIs in a Spring Boot backend.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.