Using Spring Data JPA to access MySQL in Spring Boot

Spring Data JPA is a data access layer framework provided by the Spring framework to simplify the development of JPA (Java Persistence API). It simplifies the operation of JPA data access by providing a set of convenient APIs and tools, and also provides some additional functions, such as dynamic query, paging, sorting, etc.

After we have experienced real development, we will find that in the actual development process, our operations on the database are mainly “add, delete, modify and check”. For the most common single-table operations, except for the different tables and fields, the statements are basically similar. As developers, we often need to write a large number of similar and not boring statement classes to complete the business logic I need.

In order to avoid these repetitive and boring operations, some developers provide us with many excellent development frameworks, including Hibernate, MyBatis, etc. The Spring Data JPA we are focusing on today is based on Hibernate. The Hibernate architecture is as follows:


Don’t underestimate this picture. In 2023, the software architect exam in November will take this picture.

Because Spring Data JPA depends on Hibernate. Next we use Spring Data JPA around a demo.

JPA dependency

To use Spring Data JPA, you first need to introduce the corresponding dependencies into the project. In the Maven project, you can add the following dependencies in the pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Demo dependencies:

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
        <dependency>
            <groupId>com.oracle.ojdbc</groupId>
            <artifactId>ojdbc8</artifactId>
            <version>19.3.0.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

Configure connection MYSQL configuration class

Configure database connection information in the Spring Boot configuration file, and automatically create and delete tables. The last line is as follows:

spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true & amp;characterEncoding=utf-8 & amp;useSSL=true & amp;serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

server.port=1001
#spring.datasource.url=jdbc:oracle:thin:@localhost:1521/orcl
#spring.datasource.username=root
#spring.datasource.password=root
#spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver

#hibernateconfiguration
spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop

spring.jpa.properties.hibernate.hbm2ddl.auto is a configuration property of hibernate. Its main function is to automatically create, update, and verify the database table structure. Several configurations of this parameter are as follows:

  • create: Each time hibernate is loaded, the last generated table will be deleted, and then a new table will be generated based on your model class. This is done even if there are no changes twice. This is the reason An important reason for database table data loss.
  • create-drop: The table is generated based on the model class every time hibernate is loaded, but the table is automatically deleted as soon as the sessionFactory is closed.
  • update: The most commonly used attribute. When hibernate is loaded for the first time, the table structure will be automatically established based on the model class (provided that the database is established first). When hibernate is loaded later, the table structure will be automatically updated based on the model class. , even if the table structure changes but the rows in the table still exist, the previous rows will not be deleted. It should be noted that when deployed to the server, the table structure will not be established immediately, but will wait until the application is run for the first time.
  • validate: Every time hibernate is loaded, the database table structure will be verified and created. It will only be compared with the table in the database. No new table will be created, but new values will be inserted.

User entity class

@Entity
//@Data
//@NoArgsConstructor
public class User {<!-- -->

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private Integer age;

    public User(String name, Integer age) {<!-- -->
        this.name = name;
        this.age = age;
    }

    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 Integer getAge() {<!-- -->
        return age;
    }

    public void setAge(Integer age) {<!-- -->
        this.age = age;
    }

    public User(Long id, String name, Integer age) {<!-- -->
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public User() {<!-- -->
    }

    @Override
    public String toString() {<!-- -->
        return "User{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", age=" + age +
                '}';
    }
    
}

The @Entity annotation identifies the User class as a persistent entity
@Data and @NoArgsConstructor are annotations in Lombok. Used to automatically generate the Set and Get functions for each parameter and the constructor without parameters. (The blogger doesn’t like to use the annotations here directly, so they are all built manually)
@Id and @GeneratedValue are used to identify the primary key in the corresponding database table of User.

Create an interface

The User entity creates a corresponding Repository interface to implement data access to the entity:

public interface UserRepository extends JpaRepository<User, Long> {<!-- -->

    User findByName(String name);

    User findByNameAndAge(String name, Integer age);

    @Query("from User u where u.name=:name")
    User findUser(@Param("name") String name);
}

In Spring Data JPA, you only need to write an interface similar to the above to achieve data access. We no longer need to write the interface implementation class ourselves when we wrote the interface in the past, which directly reduces our file list.

Below is some explanation of the above UserRepository. This interface inherits from JpaRepository. By viewing the API document open in new window of the JpaRepository interface, you can It can be seen that the interface itself has implemented functions for basic operations such as create (save), update (save), delete (delete), and query (findAll, findOne). Therefore, developers do not need to perform data access for these basic operations themselves. definition.

In our actual development, the interface defined by the JpaRepository interface is often not enough or the performance is not optimized enough. We need to further implement more complex queries or operations.
User findByName(String name)
User findByNameAndAge(String name, Integer age)

They respectively implement querying User entities by name and querying User entities by name and age. You can see that we have completed two conditional query methods without any SQL-like statements here. This is a great feature of Spring-data-jpa: creating queries by parsing method names.

In addition to creating queries by parsing method names, it also provides the ability to create queries by using the @Query annotation. You only need to write a JPQL statement and map the parameters specified by @Param through something like ":name" , just like the third findUser function in the example.

Create a test class

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {<!-- -->

    @Autowired
    private UserRepository userRepository;

    @Test
    public void test() throws Exception {<!-- -->

        //Create 10 records
        userRepository.save(new User(1l,"AAA", 10));
        userRepository.save(new User(2l,"BBB", 20));
        userRepository.save(new User(3l,"CCC", 30));
        userRepository.save(new User(4l,"DDD", 40));
        userRepository.save(new User(5l,"EEE", 50));
        userRepository.save(new User(6l,"FFF", 60));
        userRepository.save(new User(7l,"GGG", 70));
        userRepository.save(new User(8l,"HHH", 80));
        userRepository.save(new User(9l,"III", 90));
        userRepository.save(new User(10l,"JJJ", 100));

        //Test findAll, query all records
        Assert.assertEquals(10, userRepository.findAll().size());

        //Test findByName, query the User whose name is FFF
        Assert.assertEquals(60, userRepository.findByName("FFF").getAge().longValue());

        //Test findUser, query the User whose name is FFF
        Assert.assertEquals(60, userRepository.findUser("FFF").getAge().longValue());

        //Test findByNameAndAge, query the User whose name is FFF and whose age is 60
        Assert.assertEquals("FFF", userRepository.findByNameAndAge("FFF", 60).getName());

        //Test to delete the User named AAA
        userRepository.delete(userRepository.findByName("AAA"));

        //Test findAll, query all records, and verify whether the above deletion is successful.
        Assert.assertEquals(9, userRepository.findAll().size());

    }
}

At this point, the Spring Data JPA case is over. In Spring Data JPA, it mainly covers the abstraction of relational databases and the implementation of other data storage middleware, such as our commonly used Redis, MongoDB, ElasticSearch, etc.