Access a database with JPA and Hibernate
Learn how to access a database with JPA and Hibernate using the Micronaut framework.
On this guide
In this section
Getting Started
In this guide, we will create a Micronaut application written in Groovy.
In this guide, we will write a Micronaut application that exposes some REST endpoints and stores data in a database using JPA and Hibernate.
What you will need
To complete this guide, you will need the following:
-
Some time on your hands
-
A decent text editor or IDE (e.g. IntelliJ IDEA)
-
JDK 21 or greater installed with
JAVA_HOMEconfigured appropriately
Solution
We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.
-
Download and unzip the source
Writing the Application
Create an application using the Micronaut Command Line Interface or with Micronaut Launch.
mn create-app example.micronaut.micronautguide --build=maven --lang=groovy|
Note
|
If you don’t specify the --build argument, Gradle with the Kotlin DSL is used as the build tool. If you don’t specify the --lang argument, Java is used as the language.If you don’t specify the --test argument, JUnit is used for Java and Kotlin, and Spock is used for Groovy.
|
The previous command creates a Micronaut application with the default package example.micronaut in a directory named micronautguide.
Data Source Dependencies
Add the following dependencies:
Data Source Configuration
Define the data source in src/main/resources/application.properties.
datasources.default.password=${JDBC_PASSWORD:""}
datasources.default.url=${JDBC_URL:`jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE`}
datasources.default.username=${JDBC_USER:sa}
datasources.default.driver-class-name=${JDBC_DRIVER:org.h2.Driver}|
Note
|
This way of defining the datasource properties means that we can externalize the configuration, for example for production environment, and also provide a default value for development. If the environment variables are not defined the Micronaut framework will use the default values. Also keep in mind that it is necessary to escape the : in the connection URL using backticks `.
|
JPA configuration
Add the following snippet to src/main/resources/application.properties to configure JPA:
jpa.default.properties.hibernate.hbm2ddl.auto=update
jpa.default.properties.hibernate.show_sql=trueDomain
Create the domain entities:
package example.micronaut.domain
import com.fasterxml.jackson.annotation.JsonIgnore
import groovy.transform.CompileStatic
import io.micronaut.serde.annotation.Serdeable
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.Id
import jakarta.persistence.OneToMany
import jakarta.persistence.Table
import jakarta.validation.constraints.NotNull
import static jakarta.persistence.GenerationType.AUTO
@CompileStatic
@Serdeable
@Entity
@Table(name = 'genre')
class Genre {
@Id
@GeneratedValue(strategy = AUTO)
Long id
@NotNull
@Column(name = 'name', nullable = false, unique = true)
String name
@JsonIgnore
@OneToMany(mappedBy = 'genre')
Set<Book> books = []
Genre() {}
Genre(@NotNull String name) {
this.name = name
}
@Override
String toString() {
"Genre{id=$id, name='$name'}"
}
}The previous domain has a OneToMany relationship with the domain Book.
package example.micronaut.domain
import groovy.transform.CompileStatic
import io.micronaut.serde.annotation.Serdeable
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.Id
import jakarta.persistence.ManyToOne
import jakarta.persistence.Table
import jakarta.validation.constraints.NotNull
import static jakarta.persistence.GenerationType.AUTO
@CompileStatic
@Serdeable
@Entity
@Table(name = 'book')
class Book {
@Id
@GeneratedValue(strategy = AUTO)
Long id
@NotNull
@Column(name = 'name', nullable = false)
String name
@NotNull
@Column(name = 'isbn', nullable = false)
String isbn
@ManyToOne
Genre genre
Book() {}
Book(@NotNull String isbn,
@NotNull String name,
Genre genre) {
this.isbn = isbn
this.name = name
this.genre = genre
}
@Override
String toString() {
"Book{id=$id, name='$name', isbn='$isbn', genre=$genre}"
}
}Application Configuration
Create an interface to encapsulate the application configuration settings:
package example.micronaut
interface ApplicationConfiguration {
int getMax()
}Like Spring Boot and Grails, in Micronaut applications you can create typesafe configuration by creating classes that are annotated with @ConfigurationProperties.
Create an ApplicationConfigurationProperties class:
You can override max if you add to your src/main/resources/application.properties:
application.max=50Validation
Micronaut validation is built on the standard framework – JSR 380, also known as Bean Validation 2.0. Micronaut Validation has built-in support for validation of beans that are annotated with jakarta.validation annotations.
To use Micronaut Validation, you need the following dependencies:
<dependency>
<groupId>io.micronaut.validation</groupId>
<artifactId>micronaut-validation-processor</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut.validation</groupId>
<artifactId>micronaut-validation</artifactId>
<scope>compile</scope>
</dependency>Alternatively, you can use Micronaut Hibernate Validator, which uses Hibernate Validator; a reference implementation of the validation API.
Repository Access
Next, create a repository interface to define the operations to access the database.
package example.micronaut
import example.micronaut.domain.Genre
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotNull
interface GenreRepository {
Optional<Genre> findById(long id)
Genre save(@NotBlank String name)
Genre saveWithException(@NotBlank String name)
void deleteById(long id)
List<Genre> findAll(@NotNull SortingAndOrderArguments args)
int update(long id, @NotBlank String name)
}To mark the transaction demarcations, we use the Jakarta jakarta.transaction.Transactional annotation.
Write the implementation:
|
Note
|
When you use the Micronaut Data annotation processor, the framework maps the jakarta.transaction.Transactional annotation to io.micronaut.transaction.annotation.Transactional. In the previous code sample, we must use Micronaut @Transactional/@ReadOnly annotations, and we cannot use jakarta.transaction annotations since we don’t use Micronaut Data in this tutorial.
|
Controller
Create two classes to encapsulate Save and Update operations:
package example.micronaut
import groovy.transform.CompileStatic
import io.micronaut.serde.annotation.Serdeable
import jakarta.validation.constraints.NotBlank
@CompileStatic
@Serdeable
class GenreUpdateCommand {
long id
@NotBlank
String name
GenreUpdateCommand(long id, String name) {
this.id = id
this.name = name
}
}Create a POJO to encapsulate Sorting and Pagination:
Create GenreController, a controller which exposes a resource with the common CRUD operations:
Writing Tests
Create a test to verify the CRUD operations:
Testing the Application
To run the tests:
./mvnw testRunning the Application
To run the application, use the ./mvnw mn:run command, which starts the application on port 8080.
Using PostgreSQL
When running in production, you want to use a real database instead of using H2. Let’s explain how to use PostgreSQL.
After installing Docker, execute the following command to run a PostgreSQL container:
docker run -it --rm \
-p 5432:5432 \
-e POSTGRES_USER=dbuser \
-e POSTGRES_PASSWORD=theSecretPassword \
-e POSTGRES_DB=micronaut \
postgres:11.5-alpineAdd PostgreSQL driver dependency:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>To use PostgreSQL, set up several environment variables which match those defined in application.properties:
export JDBC_URL=jdbc:postgresql://localhost:5432/micronaut
export JDBC_USER=dbuser
export JDBC_PASSWORD=theSecretPassword
export JDBC_DRIVER=org.postgresql.DriverRun the application again. If you look at the output you can see that the application uses PostgreSQL:
..
...
08:40:02.746 [main] INFO org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL10Dialect
....Connect to your PostgreSQL database, and you will see both genre and book tables.
Save one genre, and your genre table will now contain an entry.
curl -X "POST" "http://localhost:8080/genres" \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{ "name": "music" }'Next Steps
Read more about the Configurations for Data Access section in the Micronaut documentation.
Help with the Micronaut Framework
The Micronaut Foundation sponsored the creation of this Guide. A variety of consulting and support services are available.
License
|
Note
|
All guides are released with an Apache License 2.0 for the code and a Creative Commons Attribution 4.0 license for the writing and media (images). |