In my previous tutorial, I showed you all an overview of Spring Data JPA and made an example of using the findById() method available in the JpaRepository interface to query the database for the data in the primary key column and method findByName() to retrieve student information by name. As you saw, there is no class implementing the HelloRepository interface, but we still get the information we want. This is a great feature of Spring Data JPA, don’t you? 😀 To do that, you must follow the Spring Data JPA syntax in naming a method. How is it in detail? Let’s find out in this tutorial.
First, I will also create a Maven project as an example:
The structure of this project is similar to the preparatory steps we have done in the tutorial Overview about Spring Data JPA.
We will use Java 17 for this example:
1 2 3 4 |
<properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> |
Maven dependencies:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> <scope>provided</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>6.2.6.Final</version> </dependency> |
spring.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <jpa:repositories base-package="com.huongdanjava.springdatajpa"/> <context:annotation-config/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="persistenceUnitName" value="springdataPU"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/jpa_example"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> </beans> |
persistence.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="springdataPU" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <class>com.huongdanjava.springdatajpa.Student</class> <exclude-unlisted-classes/> <properties> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="false"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> <property name="hibernate.connection.driver_class" value="com.mysql.cj.jdbc.Driver"/> <property name="javax.persistence.validation.mode" value="none"/> </properties> </persistence-unit> </persistence> |
Table student:
1 2 3 4 5 6 |
CREATE TABLE `student` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `clazz` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; |
The database currently has student information as follows:
Student entity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package com.huongdanjava.springdatajpa; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; import java.io.Serializable; import lombok.Getter; import lombok.Setter; @Table(name = "student") @Entity @Getter @Setter public class Student implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue private Long id; @Column private String name; @Column private String clazz; } |
The StudentRepository class has the following content:
1 2 3 4 5 6 7 |
package com.huongdanjava.springdatajpa; import org.springframework.data.jpa.repository.JpaRepository; public interface StudentRepository extends JpaRepository<Student, Long> { } |
The application class also has the following content:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.huongdanjava.springdatajpa; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); StudentRepository studentRepository = (StudentRepository) ac.getBean("studentRepository"); } } |
OK, the preparation steps are finished, now we go to the main topic of this tutorial.
Now, I’ll list all of the rules for naming a method in the Spring Data JPA, so that we do not need to implement the interface to get the data we need.
First of all, the name of the method, you must write it starting with one of the following names: find … By, read … By, query … By, count … By, and get … By. And then the attribute name of the entity you want to find.
Suppose, I now find student information in class as follows:
1 2 3 4 5 6 7 8 9 10 |
package com.huongdanjava.springdatajpa; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; public interface StudentRepository extends JpaRepository<Student, Long> { public List<Student> readByClazz(String clazz); } |
When you run, you will see the results as follows:
Or find the student named Khanh as follows:
1 2 3 4 5 6 7 8 |
package com.huongdanjava.springdatajpa; import org.springframework.data.jpa.repository.JpaRepository; public interface StudentRepository extends JpaRepository<Student, Long> { public Integer countByName(String name); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.huongdanjava.springdatajpa; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); StudentRepository studentRepository = (StudentRepository) ac.getBean("studentRepository"); Integer countByName = studentRepository.countByName("Khanh"); System.out.println(countByName); } } |
Result:
If you want to limit the number of records returned, you can add the First or Top together with the number of records that you want to return before By in the name of the method in the above syntax.
If there is no record number passed, only 1 record is returned by default.
Eg:
1 2 3 4 5 6 7 8 |
package com.huongdanjava.springdatajpa; import org.springframework.data.jpa.repository.JpaRepository; public interface StudentRepository extends JpaRepository<Student, Long> { public Student findFirstByName(String name); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.huongdanjava.springdatajpa; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); StudentRepository studentRepository = (StudentRepository) ac.getBean("studentRepository"); Student student = studentRepository.findFirstByName("Khanh"); System.out.println(student.getId()); } } |
Result:
If you want to find with many different conditions, then the method name must be associated with multiple attribute names of the entity and you must have multiple parameters for the method.
These parameters must be in the same order as the order of the attribute names in your method name.
For example, suppose you look for the student’s name and class, your method name should be findByNameAndClazz (String name, String clazz), the two parameter name and clazz must be in the same order as the method name.
1 2 3 4 5 6 7 8 9 10 |
package com.huongdanjava.springdatajpa; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; public interface StudentRepository extends JpaRepository<Student, Long> { public List<Student> findByNameAndClazz(String name, String clazz); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package com.huongdanjava.springdatajpa; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); StudentRepository studentRepository = (StudentRepository) ac.getBean("studentRepository"); List<Student> students = studentRepository.findByNameAndClazz("Khanh", "C"); System.out.println(students.size()); } } |
Result:
We can also order the returned result by adding OrderBy…Asc (incremental) or OrderBy...Desc (descending) to the end of the method name.
The three dots are the property names of the entities we use to order.
For example:
1 2 3 4 5 6 7 8 9 10 |
package com.huongdanjava.springdatajpa; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; public interface StudentRepository extends JpaRepository<Student, Long> { public List<Student> findByClazzOrderByNameDesc(String clazz); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package com.huongdanjava.springdatajpa; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); StudentRepository studentRepository = (StudentRepository) ac.getBean("studentRepository"); List<Student> students = studentRepository.findByClazzOrderByNameDesc("A"); students.forEach(s -> System.out.println(s.getName())); } } |
Result:
Notice that: for each of the above examples, you will see the SQL statement that Spring Data JPA has generated. Look at that, you can understand more how Spring Data JPA 😀