Spring Boot, MyBatis One-to-Many and One-to-One Selects - Annotations Example
In this section, we will learn how to handle One-to-Many and One-to-One selects in Spring Boot, MyBatis application (Annotations example).
Technologies used:
- Spring Boot 3.0.2
- MyBatis 3
- Java 17
- Maven
- H2 Database
Creating a simple spring boot web application:
First, open the Spring initializr https://start.spring.io/
Then, Provide the Group and Artifact name. We have provided Group name com.knf.dev.demo and Artifact spring-boot-mybatis-one-to-many-one-to-one. Here I selected the Maven project - language Java 17 - Spring Boot 3.0.2 and add Spring web dependency, MyBatis Framework and H2 Database.
Final Project directory:
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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-boot-mybatis-one-to-many-one-to-one</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-mybatis-one-to-many-one-to-one</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Create tables and load initial data.
schema.sql
CREATE TABLE IF NOT EXISTS users
(
email CHARACTER VARYING(30) NOT NULL,
name CHARACTER VARYING(30),
PRIMARY KEY (email)
);
CREATE TABLE IF NOT EXISTS cards
(
PRIMARY KEY (id),
id INTEGER NOT NULL,
cardnumber CHARACTER VARYING(30),
cardtype CHARACTER VARYING(50),
email CHARACTER VARYING(50),
CONSTRAINT fk_group
FOREIGN KEY(email)
REFERENCES users(email)
);
data.sql
insert into users (email, name) values ('alpha@gmail.com', 'Alpha');
insert into users (email, name) values ('beta@gmail.com', 'Beta');
insert into users (email, name) values ('gama@gmail.com', 'Gama');
insert into cards (id, cardnumber, cardtype, email)
values (1, '11111111', 'Mastercard', 'gama@gmail.com');
insert into cards (id, cardnumber, cardtype, email)
values (2, '22222222', 'Visa', 'gama@gmail.com');
insert into cards (id, cardnumber, cardtype, email)
values (3, '33333333', 'PayPal', 'gama@gmail.com');
insert into cards (id, cardnumber, cardtype, email)
values (4, '4444444', 'Visa', 'beta@gmail.com');
insert into cards (id, cardnumber, cardtype, email)
values (5, '5555555', 'PayPal', 'beta@gmail.com');
insert into cards (id, cardnumber, cardtype, email)
values (6, '6666666', 'Mastercard', 'alpha@gmail.com');
insert into cards (id, cardnumber, cardtype, email)
values (7, '7777777', 'Visa', 'alpha@gmail.com');
application.properties
logging.level.com.knf.dev.demo=TRACE
Create User Bean
package com.knf.dev.demo.model;
import java.util.List;
public class User {
private String email;
private String name;
private List<Card> cards;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Card> getCards() {
return cards;
}
public void setCards(List<Card> cards) {
this.cards = cards;
}
}
Create Card Bean
package com.knf.dev.demo.model;
public class Card {
private Integer id;
private String cardNumber;
private String cardType;
private String email;
private User user;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public String getCardType() {
return cardType;
}
public void setCardType(String cardType) {
this.cardType = cardType;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Create User Repository
@Mapper: indicates that this is a MyBatis mapper class.
@Select: We need to provide select query as value.
@Results: A list of Result mappings that contain details of how a particular result column is mapped to a property or field.
@Result: A single result mapping between a column and a property or field.
@Many: The annotation that specify the nested statement for retrieving collections.
package com.knf.dev.demo.repository;
import com.knf.dev.demo.model.Card;
import com.knf.dev.demo.model.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface UserRepository {
/*
* one to many Select.
*/
@Select("SELECT users.name, users.email " +
"FROM users WHERE users.email = #{email}")
@Results(value = {
@Result(property = "email", column = "email"),
@Result(property="cards", javaType=List.class, column="email",
many=@Many(select="getCards"))
})
User selectUserById(String email);
@Select("SELECT cards.id, cards.cardnumber, cards.cardtype, " +
"cards.email FROM cards WHERE cards.email = #{email}")
@Results(value = {
@Result(property = "cardNumber", column = "cardnumber"),
@Result(property = "cardType", column = "cardtype")
})
List<Card> getCards(String email);
}
Create Card Repository
@One: The annotation that specify the nested statement for retrieving single object.
package com.knf.dev.demo.repository;
import com.knf.dev.demo.model.Card;
import com.knf.dev.demo.model.User;
import org.apache.ibatis.annotations.*;
@Mapper
public interface CardRepository {
/*
* one to one Select.
*/
@Select("SELECT cards.id, cards.email, " +
"cards.cardnumber, cards.cardtype" +
" FROM cards WHERE cards.id = #{id}")
@Results(value = {
@Result(property = "email", column = "email"),
@Result(property = "cardNumber", column = "cardnumber"),
@Result(property = "cardType", column = "cardtype"),
@Result(property = "user", column = "email",
one=@One(select = "getUser"))
})
Card selectCardById(Integer id);
@Select("SELECT users.name, users.email FROM " +
"users WHERE users.email = #{email}")
User getUser(String email);
}
Create User Controller
package com.knf.dev.demo.controller;
import com.knf.dev.demo.model.Card;
import com.knf.dev.demo.model.User;
import com.knf.dev.demo.repository.CardRepository;
import com.knf.dev.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/")
public class UserController {
@Autowired
UserRepository userRepository;
@Autowired
CardRepository cardRepository;
@GetMapping("users/{email}")
public User getUserById(@PathVariable String email)
{
return userRepository.selectUserById(email);
}
@GetMapping("cards/{id}")
public Card getCardById(@PathVariable Integer id)
{
return cardRepository.selectCardById(id);
}
}
Run the application - Application.java
package com.knf.dev.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application is the entry point that sets up the Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning.
Step1: Download or clone the source code from GitHub to a local machine - Click here!
Step 2: mvn clean install
Step 3: Run the Spring Boot application - mvn spring-boot:run
OR
Run this Spring boot application from
- IntelliJ IDEA IDE by right click - Run 'Application.main()'
- Eclipse/STS - You can right click the project or the Application.java file and run as java application or Spring boot application.
Step1: Download or clone the source code from GitHub to a local machine - Click here!
Step 2: mvn clean install
Step 3: Run the Spring Boot application - mvn spring-boot:run
OR
Run this Spring boot application from
- IntelliJ IDEA IDE by right click - Run 'Application.main()'
- Eclipse/STS - You can right click the project or the Application.java file and run as java application or Spring boot application.
Verify APIs using Postman:
1. Get User by ID (email): localhost:8080/api/v1/users/beta@gmail.com
2. Get Card by ID: localhost:8080/api/v1/cards/4
More....