JPA(Java Persistence API) 是指Java中数据对象持久化的过程。所谓持久化是指将内存中创建的数据对象永久的保存在数据库中,即在Java中我们通过JDBC连接数据库并进行增删改查的过程。在JDBC的基础上又出现了许多持久层框架用于简化Java和数据库的交互,其中两个较为流行的框架–Hibernate和Mybatis。但是我们依旧需要在Java中编写调用数据库的接口函数,为了统一和简化这个过程,SpringDataJPA在Hibernate的基础上基于JPA标准统一定义了操作数据库函数的相关接口,这样我们可以按照规范直接使用定义好的接口函数来操作数据库。
首先通过gradle引入SpringDataJPA的依赖以及JDBC数据库连接依赖
dependencies {
implementation('org.springframework.boot:spring-boot-starter-data-jpa') //Spring Data JPA
implementation('mysql:mysql-connector-java')
......
}
接着在application.properties文件中配置数据库连接和设置SpringJPA。其中ddl-auto
代表对数据表的操作方式,如果为create
则每次都会为实体对象创建新的数据表,例如为User对象在数据库中创建user表,如果已经存在则会删除原有表。若为update
代表在原有表的基础上进行更新。
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost/blog
spring.datasource.username=root
spring.datasource.password=123456
# 控制台打印数据库查询语句
spring.jpa.show-sql=true
# 在原有数据表上进行更新
spring.jpa.hibernate.ddl-auto=update
如下所示创建一个Java实体类User
,在其中定义五个字段并生成对应的getter/setter方法,并且需要创建一个空的构造函数User()
。
使用@Entity
表明这是一个实体类,并使用@Id
指明主键,@GeneratedValue
指明主键的生成策略,这里使用IDENTITY代表由数据库自动生成自增主键。
package com.tory.blog.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Date;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
private Date createTime;
public User() {
}
//... getter/seter方法...
}
SpringDataJPA把对数据库的相关操作都封装在JPA接口中,通过继承接口就可以直接使用操作数据库的方法。按照不同用途SpringJPA提供了不同的接口,比如CrudRepository
为封装了常用的数据库增删改查操作的接口,在此基础上PagingAndSortingRepository
接口封装了数据分页的函数
public interface CrudRepository<T, ID> extends Repository<T, ID> {
//保存实体对象
<S extends T> S save(S entity);
//保存多个实体对象
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
//根据id查找对象
Optional<T> findById(ID id);
//根据id判断对象是否存在
boolean existsById(ID id);
//返回所有实体
Iterable<T> findAll();
//根据id查询多个实体
Iterable<T> findAllById(Iterable<ID> ids);
//统计实体个数
long count();
//根据id进行删除
void deleteById(ID id);
//根据实体对象进行删除
void delete(T entity);
//删除多个实体
void deleteAll(Iterable<? extends T> entities);
//删除所有
void deleteAll();
}
我们可以在上面接口的基础上自定义操作数据库的接口函数,如下所示为继承自CrudRepository的UserRepo
接口,并且新增自定义了一些数据库操作函数。SpringJPA可以根据规范的方法名自动生成相应的数据库操作方法,例如我们定义了findByUsername()
方法,它会自动根据username字段查找并返回User对象数组。Distinct
可以返回不重复的结果,OrderBy
可以对返回结果进行排序。
package com.tory.blog.repository;
import com.tory.blog.entity.User;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface UserRepo extends CrudRepository<User, Long> {
//根据方法名生成操作函数
List<User> findByUsername(String username);
//使用Distinct
List<User> findDistinctByUsername(String username);
//使用OrderBy
List<User> findByUsernameOrderByCreateTime(String username);
}
如下所示直接在Spring的controller层中调用JPA接口完成和数据库的交互,首先通过@Autowire实例化userRepo
对象完成数据库相关操作。
其中用userRepo.findAll()
查询所有用户的信息。
userRepo.findById()
根据id查询用户信息,需要注意的是该方法返回的是Optional
类型的结果,如果查询到结果会放在Optional中,若无则Optional为空。可以通过isPresent()
判断结果集是否为空,若非空可以通过get()
获取结果集中的数据。
通过userRepo.save()
实现对象数据的保存。userRepo.deleteById()
实现对象的删除。
package com.tory.blog.controller;
import com.tory.blog.entity.User;
import com.tory.blog.repository.UserRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Date;
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserRepo userRepo;
//查询所有用户信息
@GetMapping("list")
public ModelAndView index() {
return new ModelAndView("user/list", "userList", userRepo.findAll());
}
//根据id查询单个用户信息
@GetMapping("{id}")
public ModelAndView getById(@PathVariable("id") Long id) {
ModelAndView modelAndView = new ModelAndView();
if (userRepo.findById(id).isPresent()) { //若查询结果不为空
modelAndView.addObject("user", userRepo.findById(id).get());
}
modelAndView.setViewName("user/user");
return modelAndView;
}
//新增用户
@GetMapping("add")
public ModelAndView add() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user", new User());
modelAndView.addObject("title", "添加用户");
modelAndView.setViewName("user/form");
return modelAndView;
}
//修改用户信息
@GetMapping("modify/{id}")
public ModelAndView modify(@PathVariable("id") Long id) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user", userRepo.findById(id).get());
modelAndView.addObject("title", "修改信息");
modelAndView.setViewName("user/form");
return modelAndView;
}
//保存用户user对象
@PostMapping("save")
public ModelAndView saveUser(User user) {
user.setCreateTime(new Date());
userRepo.save(user);
return new ModelAndView("redirect:/user/list");
}
//删除用户
@GetMapping("delete/{id}")
public ModelAndView delete(@PathVariable("id") Long id) {
userRepo.deleteById(id);
return new ModelAndView("redirect:/user/list");
}
}
前端表单页面如下
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}">title>
<script th:replace="common/head::static">script>
head>
<body>
<form action="/user/save" method="post" th:object="${user}">
<input type="hidden" name="id" th:value="*{id}"/>
姓名:<input type="text" name="username" th:value="*{username}"/><br>
邮箱:<input type="text" name="email" th:value="*{email}"/> <br>
密码:<input type="password" name="password" th:value="*{password}"/> <br>
<input type="submit" value="提交">
form>
body>
html>
当用户访问/user/add页面,填写并提交表单后会发送post请求到/user/save,来到Controller的saveUser()
方法,这时Spring会根据表单中的name属性生成相应的User对象,之后调用userRepo.save()
将user对象持久化到数据库中。数据表user如下所示: