JPA One-to-One Mapping

Last Updated : 23 Apr, 2026

JPA One-to-One mapping defines a relationship where one entity is associated with exactly one instance of another entity. It is commonly used when two tables share a direct and exclusive relationship.

  • Uses @OneToOne annotation to map the relationship between entities
  • Can be uni-directional or bi-directional depending on access requirements
  • Often implemented using a foreign key or shared primary key in the database

Real World Example: A Person entity can have exactly one Address entity associated with it.

Types of One-to-One Mappings

  • Shared Primary Key: In this mapping, the primary key of one entity also acts as the primary key of the associated entity. This ensures a strict one-to-one relationship where both entities share the same identifier.
  • Foreign Key Association: In this approach, the associated entity maintains a foreign key column that references the primary key of the owning entity. It’s commonly used when the associated entity can exist independently.

Steps to Implement JPA One-to-One Mapping

Follow these steps to create and map a one-to-one relationship between two entities using JPA annotations in a Spring Boot application.

1. Define the Entities

Create two entities Person and Address and establish a one-to-one relationship between them using JPA annotations.

Person.java:

Java
import jakarta.persistence.*;

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne(mappedBy = "person", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Address address;

    public Person() {}

    public Long getId() { return id; }

    public void setId(Long id) { this.id = id; }

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public Address getAddress() { return address; }

    public void setAddress(Address address) { this.address = address; }
}

Address.java:

Java
import jakarta.persistence.*;

@Entity
public class Address {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "person_id")
    private Person person;

    private String city;

    public Address() {}

    public Long getId() { return id; }

    public void setId(Long id) { this.id = id; }

    public Person getPerson() { return person; }

    public void setPerson(Person person) { this.person = person; }

    public String getCity() { return city; }

    public void setCity(String city) { this.city = city; }
}
  • The @OneToOne annotation defines the one-to-one relationship.
  • The mappedBy attribute in the Person class indicates that Address owns the relationship.
  • The @JoinColumn in the Address entity defines the foreign key column (person_id).

2. Handle the Foreign Key

The foreign key column (person_id) in the Address table refers to the primary key of the Person table. This establishes a direct association between the two entities.

3. Configure Database Connection (persistence.xml)

Place the following configuration inside the META-INF/persistence.xml file.

XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence/"
             xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence/ https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
             version="3.0">

    <persistence-unit name="jpa-example">
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/example"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

4. Add Dependencies (pom.xml)

Include the following dependencies in your Maven project:

Java
<dependencies>
    <dependency>
        <groupId>org.hibernate.orm</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>6.0.2.Final</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>3.0.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

5. Create the Main Application

Java
import jakarta.persistence.*;
import model.Address;
import model.Person;

public class MainApplication {

    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-example");
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();

        Person person = new Person();
        person.setName("Mahesh");
        em.persist(person);

        Address address = new Address();
        address.setPerson(person);
        address.setCity("Hyderabad");
        em.persist(address);

        em.getTransaction().commit();

        Person retrievedPerson = em.find(Person.class, person.getId());

        if (retrievedPerson != null && retrievedPerson.getAddress() != null) {
            Address retrievedAddress = retrievedPerson.getAddress();
            System.out.println("Person: " + retrievedPerson.getName());
            System.out.println("Address: " + retrievedAddress.getCity());
        } else {
            System.out.println("Person or associated Address not found.");
        }

        em.close();
        emf.close();
    }
}

6. Run and Verify

Run the application. The console output should display the person’s name and associated address, verifying that the one-to-one mapping works correctly.

Expected Output:

oneonerun-compressed

Comment

Explore