HelloKoding

Practical coding guides

JPA and Hibernate Composite Primary Key Mapping Example with Spring Boot and MySQL

This tutorial will walk you through the steps of mapping a JPA/Hibernate composite primary key entity example with Spring Boot, Spring Data JPA, Lombok, MySQL and Docker

What you’ll need

  • You favorite IDE
  • JDK 8+ or OpenJDK 8+
  • Maven 3+
  • MySQL Server 5+ or Docker CE 18+

Init project structure and dependencies

Project structure

├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── hellokoding
│       │           └── jpa
│       │               ├── book
│       │               │   ├── Book.java
│       │               │   └── BookRepository.java
│       │               └── JpaApplication.java
│       └── resources
│           └── application.properties
├── Dockerfile
├── docker-compose.yml
└── pom.xml

Project dependencies

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hellokoding.jpa</groupId>
    <artifactId>jpa-hibernate-composite-primary-key-mysql</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Define JPA Entity and Repository

Define JPA Entity

JPA Entity is defined by @Entity annotation, represent a table in your database.

Book.java

package com.hellokoding.jpa.book;

import lombok.*;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

@Data
@NoArgsConstructor

@Entity
@IdClass(Book.IdClass.class)
public class Book {
    @Id
    private String name;

    @Id
    private Date publishedDate;

    private Date updatedDate = new Date();

    public Book(String name, Date publishedDate) {
        this.name = name;
        this.publishedDate = publishedDate;
    }

    @Data
    static class IdClass implements Serializable {
        private String name;
        private Date publishedDate;
    }
}

Composite primary key is defined by a static class IdClass. It is linked to the entity by @IdClass class annotation and @Id field annotation.

Spring Data JPA Repository

Spring Data JPA contains some built-in Repository implemented some common functions to work with database such as findOne, findAll and save. All we need for this example is extends JpaRepository.

BookRepository.java

package com.hellokoding.jpa.book;

import org.springframework.data.jpa.repository.JpaRepository;

public interface BookRepository extends JpaRepository<Book, Integer>{
}

Define Properties and Creating Data

Application Properties

application.properties

spring.datasource.url=jdbc:mysql://hk-mysql:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=hellokoding
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.hibernate.ddl-auto=create
spring.jpa.database-platform=org.hibernate.dialect.MySQL57Dialect
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true

hk-mysql refers to Docker Compose service defined in the below docker-compose.yml file

spring.jpa.hibernate.ddl-auto=create allows JPA/Hibernate auto create database and table schema for you.

In practice, you may like to disable the DDL Auto feature by using spring.jpa.hibernate.ddl-auto=validate or spring.jpa.hibernate.ddl-auto=none (default). Check out this example as one of the approaches Spring Boot Flyway Example of Database Evolution

Creating data with JPA and Hibernate

JpaApplication.java

package com.hellokoding.jpa;

import com.hellokoding.jpa.book.Book;
import com.hellokoding.jpa.book.BookRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.util.Arrays;
import java.util.Date;

@Slf4j

@SpringBootApplication
class JpaApplication {
    public static void main(String[] args) {
        SpringApplication.run(JpaApplication.class, args);
    }

    @Bean
    public CommandLineRunner runner(BookRepository bookRepository) {
        return r -> {
            // Create a couple of Book
            bookRepository.saveAll(Arrays.asList(new Book("Hello Koding 1", new Date()), new Book("Hello Koding 2", new Date())));

            // Fetch all
            log.info("My books: " + bookRepository.findAll());
        };
    }
}

Run the example

Run with Docker

Prepare Dockerfile for Java/Spring Boot application and docker-compose.yml for MySQL Server

Dockerfile

FROM maven:3.5-jdk-8

docker-compose.yml

version: '3'
services:
  hk-mysql:
    container_name: hk-mysql
    image: mysql/mysql-server:5.7
    environment:
      MYSQL_DATABASE: test
      MYSQL_ROOT_PASSWORD: hellokoding
      MYSQL_ROOT_HOST: '%'
    ports:
    - "3306:3306"
    restart: always

  app:
    build: .
    volumes:
    - .:/app
    - ~/.m2:/root/.m2
    working_dir: /app
    command: mvn clean spring-boot:run
    depends_on:
    - hk-mysql

Type the below command at the project root directory, make sure your local Docker is running

docker-compose up

Access to MySQL Server docker container by issuing below bash command and key in hellokoding on Enter password:

docker exec -it hk-mysql mysql -p

Query the schema and data created by JPA/Hibernate based on your mapping

JPA Composite Primary Key

JPA Composite Primary Key

Run with JDK/OpenJDK, Maven and MySQL Server local

  • On application.properties, update data source user name + password to your local configs, update data source url hk-mysql to localhost
  • Then type this command at the project root directory mvn clean spring-boot:run

Source code

https://github.com/hellokoding/hellokoding-courses/tree/master/jpa-hibernate-examples/jpa-hibernate-composite-primary-key-mysql

Follow HelloKoding