1、JPA(Java持久层API)
1.1 认识Spring Data
Spring Data 是Spring的一个子项目,旨在统一和简化各类型数据的持久化存储方式,而不拘泥于是关系型数据库还是NoSQL数据库。无论是哪种持久化存储方式,数据访问对象(Data Access Objects,DAO)都会提供对对象的增加、删除、修改和查询的方法,以及排序和分页方法等。
Spring Data 提供了基于这些层面的统一接口(如:CrudRepository、 PagingAndSortingRepository),以实现持久化的存储。
1.2 认识JPA
JPA(Java Persistence API)是Java的持久化API,用于对象的持久化。它是一个非常强大的ORM持久化的解决方案,免去了使用JDBCTemplate开发的编写脚本工作。JPA通过简单约定好接口方法的规则自动生成相应的JPQL语句,然后映射成POJO对象。
JPA是一个规范化接口,封装了Hibernate的操作作为默认实现,让用户不通过任何配置即可完成数据库的操作。
2、认识JPA的接口
JPA提供了操作数据库的接口。在开发过程中继承和使用这些接口,可简化现有的持久化开发工作。可以使Spring找到自定义接口,并生成代理类,后续可以把自定义接口注入Spring容器中进行管理。在自定义接口过程中,可以不写相关的SQL操作,由代理类自动生成。
2.1 JPA接口JpaRepository
JpaRepository接口继承自PagingAndSortingRepository接口。该接口提供了JPA的相关实用功能,以及通过Example进行查询的功能。Example对象是JPA提供用来构造查询条件的对象。该接口的关键代码如下:
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>
{
}
在上述代码中,T 表示实体对象,ID 表示主键。ID必须实现序列号。
JpaRepository接口的源代码如下:
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>
{
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
<S extends T> List<S> saveAll(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
JpaRepository接口提供的方法与说明:
方法 | 描述 |
---|---|
List<T> findAll(); | 查找所有实体。 |
List<T> findAll(Sort var1); | 排序、查找所有实体。 |
List<T> findAllById(Iterable<ID> var1); | 返回制定一组ID的实体。 |
<S extends T> List<S> saveAll(Iterable<S> var1); | 保存集合。 |
void flush(); | 执行缓存与数据库同步。 |
<S extends T> S saveAndFlush(S var1); | 强制执行持久化。 |
void deleteInBatch(Iterable<T> var1); | 删除一个实体集合。 |
void deleteAllInBatch(); | 删除所有实体。 |
T getOne(ID var1); | 返回ID对应的实体。如果不存在,则返回空值。 |
<S extends T> List<S> findAll(Example<S> var1); | 查询满足Example的所有对象。 |
<S extends T> List<S> findAll(Example<S> var1, Sort var2); | 查询满足Example的所有对象,并且进行排序返回。 |
2.2 数据操作接口CrudRepository
CrudRepository接口继承自Repository接口,并新增了增加、删除、修改和查询方法。
CrudRepository接口的源代码如下:
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID>
{
<S extends T> S save(S var1);
<S extends T> Iterable<S> saveAll(Iterable<S> var1);
Optional<T> findById(ID var1);
boolean existsById(ID var1);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> var1);
long count();
void deleteById(ID var1);
void delete(T var1);
void deleteAll(Iterable<? extends T> var1);
void deleteAll();
}
CrudRepository接口提供的方法与说明:
方法 | 说明 |
---|---|
<S extends T> S save(S var1); | 保存实体。当实体中包含主键时,JPA会进行更新操作。 |
<S extends T> Iterable<S> saveAll(Iterable<S> var1); | 保存所有实体。实体必须不为空。 |
Optional<T> findById(ID var1); | 根据主键ID检索实体。 |
boolean existsById(ID var1); | 根据主键ID检索实体,返回是否存在。值为布尔类型。 |
Iterable<T> findAll(); | 返回所有实体。 |
Iterable<T> findAllById(Iterable<ID> var1); | 根据给定的一组ID值返回一组实体。 |
long count(); | 返回实体的数量 |
void deleteById(ID var1); | 根据ID删除数据。 |
void delete(T var1); | 删除给定的实体。 |
void deleteAll(Iterable<? extends T> var1); | 删除实体。 |
void deleteAll(); | 删除所有实体。 |
3、使用JPA实现数据的增删改查操作
【实例】创建SpringBoot项目,使用JPA实现数据的增删改查操作。
3.1 创建数据库表
使用MySQL数据库,创建 tb_user 用户信息数据表,并添加测试数据。
-- 判断数据表是否存在,存在则删除
DROP TABLE IF EXISTS tb_user;
-- 创建“用户信息”数据表
CREATE TABLE IF NOT EXISTS tb_user
(
user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号',
user_name VARCHAR(50) NOT NULL COMMENT '用户姓名',
blog_url VARCHAR(50) NOT NULL COMMENT '博客地址',
remark VARCHAR(50) COMMENT '备注'
) COMMENT = '用户信息表';
-- 添加数据
INSERT INTO tb_user(user_name,blog_url,remark) VALUES('pan_junbiao的博客','https://blog.csdn.net/pan_junbiao','您好,欢迎访问 pan_junbiao的博客');
INSERT INTO tb_user(user_name,blog_url,remark) VALUES('pan_junbiao的博客_02','https://blog.csdn.net/pan_junbiao','您好,欢迎访问 pan_junbiao的博客');
执行结果:
3.2 创建项目并配置JPA环境
(1)创建SpringBoot项目
创建SpringBoot项目,并创建项目结构:dao(数据访问层)、service(服务层)、entity(实体层),如下图:
(2)添加JPA和MySQL数据库的依赖
在pom.xml配置文件中,添加如下依赖:
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL的JDBC数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
(3)配置数据库连接信息
SpringBoot项目使用MySQL等关系型数据库,需要配置连接信息。
将默认的application.properties文件的后缀修改为“.yml”,即配置文件名称为:application.yml,并配置以下MySQL数据库的连接信息:
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_admin?useSSL=false&
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
database: MYSQL
show-sql: true
open-in-view: true
properties:
hibernate:
enable_lazy_load_no_trans: true
dialect: org.hibernate.dialect.MySQL5Dialect
ddl-auto: update
3.3 实现增删改查代码
(1)实体层(Entity层)
在实体层(Entity层)中,创建UserInfo.java(用户信息实体类)。
package com.pjb.jpauserdemo.entity;
import javax.persistence.*;
/**
* 用户信息实体类
* @author pan_junbiao
**/
@Entity
@Table(name = "tb_user")
public class UserInfo
{
//用户ID
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private int userId;
//用户姓名
@Column(name = "user_name")
private String userName;
//博客地址
@Column(name = "blog_url")
private String blogUrl;
//备注
private String remark;
//省略getter与setter方法...
}
(2)数据库访问层(Dao层)
在数据库访问层(Dao层)中,创建UserDao.java(用户信息数据库访问接口),并继承JpaRepository接口。
package com.pjb.jpauserdemo.dao;
import com.pjb.jpauserdemo.entity.UserInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* 用户信息数据库访问接口
* @author pan_junbiao
**/
@Repository
public interface UserDao extends JpaRepository<UserInfo,Integer>
{
}
(3)业务逻辑层(Service层)
在业务逻辑层(Service层)中,创建UserService.java(用户业务逻辑接口)。
package com.pjb.jpauserdemo.service;
import com.pjb.jpauserdemo.entity.UserInfo;
import java.util.List;
/**
* 用户业务逻辑接口
* @author pan_junbiao
**/
public interface UserService
{
/**
* 根据用户ID,查询用户信息
*/
public UserInfo findById(int userId);
/**
* 查询用户列表
*/
public List<UserInfo> findAll();
/**
* 新增用户
*/
public UserInfo save(UserInfo userInfo);
/**
* 修改用户
*/
public UserInfo edit(UserInfo userInfo);
/**
* 删除用户
*/
public boolean deleteById(int userId);
}
在业务逻辑层(Service层)下,创建 impl 目录,在该目录下创建UserServiceImpl.java(用户业务逻辑类)。
package com.pjb.jpauserdemo.service.impl;
import com.pjb.jpauserdemo.dao.UserDao;
import com.pjb.jpauserdemo.entity.UserInfo;
import com.pjb.jpauserdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 用户业务逻辑类
* @author pan_junbiao
**/
@Service
public class UserServiceImpl implements UserService
{
@Autowired
private UserDao userDao;
/**
* 根据用户ID,查询用户信息
*/
@Override
public UserInfo findById(int userId)
{
return userDao.findById(userId).get();
}
/**
* 查询用户列表
*/
@Override
public List<UserInfo> findAll()
{
return userDao.findAll();
}
/**
* 新增用户
*/
@Override
public UserInfo save(UserInfo userInfo)
{
return userDao.save(userInfo);
}
/**
* 修改用户
*/
@Override
public UserInfo edit(UserInfo userInfo)
{
return userDao.save(userInfo);
}
/**
* 删除用户
*/
@Override
public boolean deleteById(int userId)
{
boolean result = true;
try
{
userDao.deleteById(userId);
}
catch(Exception ex)
{
result = false;
}
return result;
}
}
3.4 执行测试
3.4.1 查询数据
@Autowired
private UserService userService;
/**
* 测试:根据用户ID,查询用户信息
* @author pan_junbiao
*/
@Test
public void findById()
{
//查询用户编号为1的用户信息
UserInfo user = userService.findById(1);
if (user != null)
{
//打印结果
System.out.println("用户编号:" + user.getUserId());
System.out.println("用户姓名:" + user.getUserName());
System.out.println("博客地址:" + user.getBlogUrl());
System.out.println("备注信息:" + user.getRemark());
}
}
执行结果:
3.4.2 查询列表
/**
* 测试:查询用户列表
* @author pan_junbiao
*/
@Test
public void findAll()
{
//查询用户列表
List<UserInfo> userList = userService.findAll();
if (userList != null && userList.size() > 0)
{
for (UserInfo user : userList)
{
//打印结果
System.out.println("用户编号:" + user.getUserId());
System.out.println("用户姓名:" + user.getUserName());
System.out.println("博客地址:" + user.getBlogUrl());
System.out.println("备注信息:" + user.getRemark());
System.out.println("===========================================");
}
}
}
执行结果:
3.4.3 新增操作
/**
* 测试:新增用户
* @author pan_junbiao
*/
@Test
public void save()
{
//创建新用户
UserInfo user = new UserInfo();
user.setUserName("pan_junbiao的博客_03");
user.setBlogUrl("https://blog.csdn.net/pan_junbiao");
user.setRemark("您好,欢迎访问 pan_junbiao的博客");
//执行新增操作
userService.save(user);
//如果新增成功,则可以获取自增主键
//否则新增失败,则抛出异常
if (user.getUserId() > 0)
{
System.out.println("新增用户成功,新增的用户信息:");
System.out.println("用户编号:" + user.getUserId());
System.out.println("用户姓名:" + user.getUserName());
System.out.println("博客地址:" + user.getBlogUrl());
System.out.println("备注信息:" + user.getRemark());
}
}
执行结果:
查询数据表:
从查询的数据表结果中可以看到,成功新增了ID为3的用户信息。
3.4.4 修改操作
/**
* 测试:修改用户
* @author pan_junbiao
*/
@Test
public void edit()
{
//创建修改用户
UserInfo user = new UserInfo();
user.setUserId(3);
user.setUserName("pan_junbiao的博客_04");
user.setBlogUrl("https://blog.csdn.net/pan_junbiao");
user.setRemark("您好,欢迎访问 pan_junbiao的博客");
//执行修改操作
userService.edit(user);
//如果没有抛出异常,则表示执行成功
System.out.println("修改用户成功");
}
查询数据表:
从查询的数据表结果中可以看到,ID为3的用户信息已被修改。
3.4.5 删除操作
/**
* 测试:删除用户
* @author pan_junbiao
*/
@Test
public void deleteById()
{
//执行新增操作
boolean result = userService.deleteById(3);
//打印结果
if (result)
{
System.out.println("删除用户成功");
}
else
{
System.out.println("删除用户失败");
}
}
查询数据表:
从查询的数据表结果中可以看到,ID为3的用户信息已被删除。
3.4.6 完整的测试代码
package com.pjb.jpauserdemo.service.impl;
import com.pjb.jpauserdemo.entity.UserInfo;
import com.pjb.jpauserdemo.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* 用户信息业务逻辑测试类
* @author pan_junbiao
**/
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceImplTest
{
@Autowired
private UserService userService;
/**
* 测试:根据用户ID,查询用户信息
* @author pan_junbiao
*/
@Test
public void findById()
{
//查询用户编号为1的用户信息
UserInfo user = userService.findById(1);
if (user != null)
{
//打印结果
System.out.println("用户编号:" + user.getUserId());
System.out.println("用户姓名:" + user.getUserName());
System.out.println("博客地址:" + user.getBlogUrl());
System.out.println("备注信息:" + user.getRemark());
System.out.println("\n");
}
}
/**
* 测试:查询用户列表
* @author pan_junbiao
*/
@Test
public void findAll()
{
//查询用户列表
List<UserInfo> userList = userService.findAll();
if (userList != null && userList.size() > 0)
{
for (UserInfo user : userList)
{
//打印结果
System.out.println("用户编号:" + user.getUserId());
System.out.println("用户姓名:" + user.getUserName());
System.out.println("博客地址:" + user.getBlogUrl());
System.out.println("备注信息:" + user.getRemark());
System.out.println("===========================================");
}
}
}
/**
* 测试:新增用户
* @author pan_junbiao
*/
@Test
public void save()
{
//创建新用户
UserInfo user = new UserInfo();
user.setUserName("pan_junbiao的博客_03");
user.setBlogUrl("https://blog.csdn.net/pan_junbiao");
user.setRemark("您好,欢迎访问 pan_junbiao的博客");
//执行新增操作
userService.save(user);
//如果新增成功,则可以获取自增主键
//否则新增失败,则抛出异常
if (user.getUserId() > 0)
{
System.out.println("新增用户成功,新增的用户信息:");
System.out.println("用户编号:" + user.getUserId());
System.out.println("用户姓名:" + user.getUserName());
System.out.println("博客地址:" + user.getBlogUrl());
System.out.println("备注信息:" + user.getRemark());
}
}
/**
* 测试:修改用户
* @author pan_junbiao
*/
@Test
public void edit()
{
//创建修改用户
UserInfo user = new UserInfo();
user.setUserId(3);
user.setUserName("pan_junbiao的博客_04");
user.setBlogUrl("https://blog.csdn.net/pan_junbiao");
user.setRemark("您好,欢迎访问 pan_junbiao的博客");
//执行修改操作
userService.edit(user);
//如果没有抛出异常,则表示执行成功
System.out.println("修改用户成功");
}
/**
* 测试:删除用户
* @author pan_junbiao
*/
@Test
public void deleteById()
{
//执行新增操作
boolean result = userService.deleteById(3);
//打印结果
if (result)
{
System.out.println("删除用户成功");
}
else
{
System.out.println("删除用户失败");
}
}
}