In this post, I would like to take the time to write about @Query, which allows you to write queries directly in Java JPA Respository.
JPQL
Although JPA automatically generates queries for you, you may need to write your own queries in some circumstances.There are two ways to write queries directly in JPA:
- Written in JPQL
- written in plain SQL
As a query language that can be used in JPA, JPQL needs to look at and write entity classes, while plain SQL looks at databases and writes them.
The way to write queries directly in both JPQL and SQL is to use the @Query annotation in the same way. And you can distinguish whether it is written in JPQL or SQL by using the property called nativeQuery in the @Query annotation.
- nativeQuery = true → SQL
- nativeQuery = false (default) → JPQL
I'll generate the relevant code to show you how it can be written.
Let's Getting Started
First, let's set up basic settings such as creating tables and entities.[ 1. Creating tables/data in MySQL ]
create table snack (
snack_id int auto_increment,
name varchar(50),
price int,
primary key(snack_id)
);
insert into snack(name, price) values ('Honey Butter Chips', 1500);
insert into snack(name, price) values ('Swing Chip', 2000);
insert into snack(name, price) values ('Roly-Poly', 1200);
insert into snack(name, price) values ('Postick', 1600);
insert into snack(name, price) values ('potato cracker', 1600);[ 2. Snack Entity Class ]
package com.spring.jpa.dto;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "snack")
public class Snack implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "snack_id")
private int id;
private String name;
private int price;
}
package com.spring.jpa.repository;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.spring.jpa.dto.Snack;
public interface SnackRepository extends JpaRepository<Snack, Integer>{
// generic type: <entity class, primary key of entity class>
}package com.spring.jpa;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import com.spring.jpa.config.RootContext;
import com.spring.jpa.dto.Snack;
import com.spring.jpa.repository.SnackRepository;
import lombok.extern.slf4j.Slf4j;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = RootContext.class)
@Slf4j
public class JPATest {
@Autowired
SnackRepository snackRepository;
@Test
public void snackTest() {
}
}How to use @Query (general query)
[ Repository ]package com.spring.jpa.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.spring.jpa.dto.Snack;
public interface SnackRepository extends JpaRepository<Snack, Integer>{
@Query(value = "select sn from Snack sn")
public List<Snack> selectAllJPQL();
@Query(value = "select snack_id, name, price from snack", nativeQuery = true)
public List<Snack> selectAllSQL();
}[ Unit Test ]
package com.spring.jpa;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import com.spring.jpa.config.RootContext;
import com.spring.jpa.dto.Snack;
import com.spring.jpa.repository.SnackRepository;
import lombok.extern.slf4j.Slf4j;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = RootContext.class)
@Slf4j
public class JPATest {
@Autowired
SnackRepository snackRepository;
@Test
public void snackTest() {
log.info(snackRepository.selectAllJPQL().toString());
log.info(snackRepository.selectAllSQL().toString());
}
}
How to use @Query (using parameters)
[ Repository ]
package com.spring.jpa.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.spring.jpa.dto.Snack;
public interface SnackRepository extends JpaRepository<Snack, Integer>{
// In JPQL, the variable name of entity is id, so sn.id is included in the condition clause.
// JPQL general parameter query, using @Param X
@Query(value = "select sn from Snack sn where sn.id > ?1")
public List<Snack> selectJPQLById1(int id);
// JPQL general parameter query, using @Param O
@Query(value = "select sn from Snack sn where sn.id > :id")
public List<Snack> selectJPQLById2(@Param(value = "id") int id);
// Query JPQL object parameters
@Query(value = "select sn from Snack sn where sn.id > :#{#paramSnack.id}")
public List<Snack> selectJPQLById3(@Param(value = "paramSnack") Snack snack);
// Since the column name of the table is snack_id in SQL, snack_id in the condition clause
// SQL general parameter query, using @Param X
@Query(value = "select snack_id, name, price from snack where snack_id > ?1", nativeQuery = true)
public List<Snack> selectSQLById1(int id);
// SQL general parameter query, using @Param O
@Query(value = "select snack_id, name, price from snack where snack_id > :id", nativeQuery = true)
public List<Snack> selectSQLById2(@Param(value = "id") int id);
// Query SQL object parameters
@Query(value = "select snack_id, name, price from snack where snack_id > :#{#paramSnack.id}", nativeQuery = true)
public List<Snack> selectSQLById3(@Param(value = "paramSnack") Snack snack);
}
[ Unit Test ]
package com.spring.jpa;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import com.spring.jpa.config.RootContext;
import com.spring.jpa.dto.Snack;
import com.spring.jpa.repository.SnackRepository;
import lombok.extern.slf4j.Slf4j;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = RootContext.class)
@Slf4j
public class JPATest {
@Autowired
SnackRepository snackRepository;
@Test
public void snackTest() {
log.info(snackRepository.selectJPQLById1(2).toString());
log.info(snackRepository.selectJPQLById2(2).toString());
log.info(snackRepository.selectJPQLById3(new Snack(2, null, 0)).toString());
log.info(snackRepository.selectSQLById1(2).toString());
log.info(snackRepository.selectSQLById2(2).toString());
log.info(snackRepository.selectSQLById3(new Snack(2, null, 0)).toString());
}
}Thank for reading. Hope it could help you to learn more. :)
Comments
Post a Comment