Spring Boot Tutorial
Connecting Spring Boot to PostgreSQL and MySQL
The H2 in-memory database is great for your first experiments, but real applications run on a production database such as PostgreSQL or MySQL. Spring Boot makes the switch mostly a matter of adding a JDBC driver and three properties — but a production-ready setup also needs a tuned connection pool, a sensible schema strategy, profiles per environment, and a way to run the database locally.
This lesson walks through connecting to PostgreSQL and MySQL, how Spring Boot builds the DataSource and HikariCP pool, which spring.jpa settings matter, why ddl-auto=update does not belong in production, and how Docker Compose support starts your database automatically in development.
What Spring Boot Auto-Configures
With spring-boot-starter-data-jpa (or spring-boot-starter-jdbc) and a JDBC driver on the classpath, Spring Boot creates a DataSource backed by HikariCP, the fastest and default connection pool, using the spring.datasource.* properties. With JPA it also creates the EntityManagerFactory, a JpaTransactionManager, and enables Spring Data repositories. Boot usually infers the driver class from the URL, so you rarely set driver-class-name.
Connection Pool Tuning
Opening a database connection is expensive, so the pool keeps a set of open connections and lends them to requests. The most important settings are maximum-pool-size (default 10), minimum-idle, connection-timeout (how long a request waits for a free connection) and max-lifetime (should be shorter than the database's own idle timeout). A bigger pool is not automatically faster: a database with 8 CPU cores rarely benefits from more than ~20 active connections, and every application instance brings its own pool.
Schema Management: ddl-auto
spring.jpa.hibernate.ddl-auto tells Hibernate whether to touch the schema: create-drop (default for embedded databases), create, update, validate or none. update is convenient while prototyping but dangerous in production — it never drops or renames columns, cannot migrate data, and makes changes nobody reviewed. In production use validate or none and manage the schema with Flyway or Liquibase (see the migrations lesson).
Environment-Specific Configuration
Keep local defaults in application.yml, override them per environment with profiles (application-prod.yml) or environment variables (SPRING_DATASOURCE_URL, SPRING_DATASOURCE_PASSWORD). Passwords never go into committed files.
Running the Database Locally with Docker Compose
Add spring-boot-docker-compose and a compose.yaml file. When you start the application in development, Spring Boot runs docker compose up, waits for the database, and creates a service connection — the datasource URL, username and password are configured from the container automatically, so you need no spring.datasource properties locally at all.
Examples
PostgreSQL: dependencies and application.yml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
# application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/webnest
username: webnest
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 10
minimum-idle: 2
connection-timeout: 5s
max-lifetime: 30m
jpa:
hibernate:
ddl-auto: validate
open-in-view: false
properties:
hibernate:
jdbc:
batch_size: 50
order_inserts: true
HikariPool-1 - Starting...
HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@5e3a8624
HikariPool-1 - Start completed.
Initialized JPA EntityManagerFactory for persistence unit 'default'
MySQL: the same application with a different driver and URL
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/webnest?serverTimezone=UTC
username: webnest
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@2b6f7a3c
(Hibernate detects the MySQL dialect automatically from the connection metadata.)
Docker Compose: start PostgreSQL automatically in development
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<optional>true</optional>
</dependency>
# compose.yaml (project root)
services:
postgres:
image: postgres:17
environment:
POSTGRES_DB: webnest
POSTGRES_USER: webnest
POSTGRES_PASSWORD: secret
ports:
- "5432"
Using Docker Compose file D:\webnest-shop\compose.yaml
Container webnest-shop-postgres-1 Started
(datasource configured from the running container — no spring.datasource properties needed locally)
Production overrides with a profile and environment variables
# application-prod.yml
spring:
datasource:
url: ${DB_URL}
username: ${DB_USER}
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 20
jpa:
hibernate:
ddl-auto: none
docker:
compose:
enabled: false
# start command
java -jar shop.jar --spring.profiles.active=prod
The following 1 profile is active: "prod"
HikariPool-1 - Start completed.
Common Mistakes
- Using ddl-auto=update or create in production, which can silently drift or even drop the schema.
- Committing the database password in application.yml.
- Setting maximum-pool-size to 100+ "for performance", overwhelming the database when several instances start.
- Leaving spring.jpa.open-in-view enabled (the default), which keeps a connection-bound session open during view rendering and hides lazy-loading problems.
- Forgetting the JDBC driver dependency and getting "Failed to determine a suitable driver class".
Key Points to Remember
- A driver plus spring.datasource.url/username/password is enough for Spring Boot to build a HikariCP DataSource.
- Tune the pool conservatively; more connections is not automatically faster.
- Use ddl-auto=validate or none in production and manage schema changes with migrations.
- Profiles and environment variables separate local, test and production settings.
- spring-boot-docker-compose starts your database in development and wires the connection automatically.
Practice the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
Use your local JDK or project IDE for these examples. Codelab currently runs Python and HTML/CSS/JavaScript; framework examples may need project dependencies.