本文纯个人读书笔记,书籍《一步一步学 Spring Boot 2》
如果喜欢,可直接购买书籍。如有侵权,请联系删除
一、Spring Data JPA
JPA (Java Persistence API) 是 Sun 官方提出的 Java 持久化规范。 只定义标准规则,不提供实现。
而 JPA 的主要实现有 Hibernate、EclipseLink、OpenJPA 等。JPA 是一套规范,不是一套产品。Hibernate 是一套产品,如果这些产品实现了 JPA 规范,那么我们可以叫它们为 JPA 的实现产品。
Spring Data JPA 是 Spring Data 的一个子项目,它通过提供基于 JPA 的 Respository,极大地减少了 JPA 作为数据访问方案的代码量。通过 Spring Data JPA 框架,开发者可以省略实现持久层业务逻辑的工作,唯一要做的,就只是声明持久层的接口,其它都交给 Spring Data JPA 来帮你完成。
核心接口 Repository
Repository.java:
package org.springframework.data.repository;
import org.springframework.stereotype.Indexed;
@Indexed
public interface Repository<T, ID> {
}
Repository 是一个空的类,里面什么都没有。Repository 接口的子类有 CrudRepository、PagingAndSortingRepository、JpaRepository等。
CrudRepository:提供了基本的增删改查等接口,
PagingAndSortingRepository:继承 CrudRepository,提供了基本的分页和排序等接口,
JpaRepository:继承 PagingAndSortingRepository 和 QueryByExampleExecutor,提供 JPA 需要的方法。
在真实的项目当中,我们都是通过实现 JpaRepository 或者其子类进行基本的数据库操作。
JpaRepository.java:
@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);
}
@NoRepositoryBean: 使用该注解,表明此接口不是一个 Repository Bean。
二、集成 Spring Data JPA
1.引入依赖
在 pom.xml 中添加 Spring Data JPA 的依赖。
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2.实现类
新建接口 com.xiaoyue.demo.repository.UserRepository.java ,继承 JpaRepository。
UserRepository.java:
public interface UserRepository extends JpaRepository<User, String> {
}
3.实体类添加注解
这时候,我们需要对 JpaRepository 子类关联的实体类 User 添加上对应的注解。
User.java:
@Entity
@Table(name = "user")
public class User {
//主键
@Id
private String id;
//用户名
private String name;
//密码
private String password;
......
}
@Entity:每个持久化 POJO 类都是一个实体 Bean, 通过在类的定义中使用 @Entity 注解来进行声明。
@Table:声明此对象映射到数据库的数据表。该注释不是必须的,如果没有则系统使用默认值(实体的短类名)。
@Id:指定表的主键。
4.服务层
按照标准流程,新建 User 模块 service 层的接口 com.xiaoyue.service.UserService 和接口实现类 com.xiaoyue.service.impl.UserServiceImpl。
UserService .java:
public interface UserService {
User findByid(String id);
List<User> findAll();
User save(User user);
void delete(String id) ;
}
UserServiceImpl .java:
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Resource
private UserRepository userRepository;
@Override
public User findByid(String id) {
return userRepository.findById(id).get();
}
@Override
public List<User> findAll() {
return userRepository.findAll();
}
@Override
public User save(User user) {
userRepository.save(user);
return user;
}
@Override
public void delete(String id) {
userRepository.deleteById(id);
}
}
@ Service:Spring Boot 会自动扫描到 @Component 注解的类,并把这些类纳入进 Spring 容器中管理。
也可以用 @Component 注解,只是 @Service 注解更能表明该类是服务层类。
@Component:泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Repository:持久层组件,用于标注数据访问组件,即 DAO 组件 。
@Resource:这个注解属于 J2EE 的,默认安照名称进行装配,名称可以通过 name 属性进行指定。
如果没有指定 name 属性,当注解写在字段上时,默认取字段名进行查找。
如果注解写在 setter 方法上默认取属性名进行装配。 当找不到与名称匹配的 bean 时才按照类型进行装配。
但是需要注意的是,如果 name 属性一旦指定,就只会按照名称进行装配。具体代码如下:
@Resource(name = "UserRepository")
private UserRepository UserRepository;
@Autowired:这个注解是属于 Spring 的,默认按类型装配。
默认情况下要求依赖对象必须存在,
如果要允许 null 值,可以设置它的 required 属性为 false,如:@Autowired(required=false) ,
如果我们想使用名称装配可以结合 @Qualifier 注解进行使用。具体代码如下:
@Autowired
@Qualifier("ayUserRepository")
private AyUserRepository ayUserRepository;
这是一个标准的增删改查功能。
5.分页查询
分页功能在后台开发中属于十分常见的,我们在这边进行一个分页查询的开发。
在 UserService 中添加接口:
Page<User> findAll(Pageable pageable);
Pageable: 这是一个分页接口,查询时候我们只需要传入一个 Pageable 接口的实现类,指定 pageNumber 和 pageSize 即可。pageNumber 为第几页, pageSize 为每页大小。
Page: 分页查询结果会封装在该类中,Page 接口实现 Slice 接口,通过查看其源码可知。我们通过调用 getTotalPages 和 getContent 等方法,可以方便获得总页数和查询的记录。
在 UserServiceImpl 中添加具体的分页查询实现:
@Override
public Page<User> findAll(Pageable pageable) {
return userRepository.findAll(pageable);
}
6.自定义查询
JpaRepository 提供的接口能满足大部分需求,如果说还需要其他扩展的话,我们可以进行自定义接口的开发。
在 UserRepository 中添加自定义查询方法。
UserRepository.java:
public interface UserRepository extends JpaRepository<User, String> {
/**
* 描述:通过名字相等查询,参数为 name
* 相当于:select u from user u where u.name = ?
*/
List<User> findByName(String name);
/**
* 描述:通过名字 like 查询,参数为 name
* 相当于:select u from user u where u.name like ?
*/
List<User> findByNameLike(String name);
/**
* 描述:通过主键 id 集合查询,参数为 id 集合
* 相当于:select u from user u where u.id in (?,?,?)
*/
List<User> findByIdIn(Collection<String> ids);
}
Spring Data JPA 有一套完整的规范,只要我们按照规范编写代码,Spring Data JPA 就会根据自动翻译成相关的 SQL 语句,进行数据库查询。
比如我们可以使用 findBy、Like、In 等关键字。其中 findBy 可以用 read、readBy、query、queryBy、get、getBy 来代替。
关于查询关键字的更多内容,大家可以到 官网 进行查看。
在 UserService 中添加对应的接口:
List<User> findByName(String name) ;
List<User> findByNameLike(String name) ;
List<User> findByIdIn(Collection<String> ids) ;
在 UserServiceImpl 中添加对应的实现:
@Override
public List<User> findByName(String name) {
return userRepository.findByName(name);
}
@Override
public List<User> findByNameLike(String name) {
return userRepository.findByNameLike(name);
}
@Override
public List<User> findByIdIn(Collection<String> ids) {
return userRepository.findByIdIn(ids);
}
三、测试
在测试类 DemoApplicationTests 中添加测试代码。
DemoApplicationTests.java:
@Resource
private UserService userService ;
@Test
public void testRepository() {
// 查询所有数据
List<User> userList = userService.findAll () ;
System.out.println("findAll():" + userList.size());
// 通过 name 查询数据
List<User> userList2 = userService.findByName("zx") ;
System.out.println("findByName () :" + userList2.size());
for (User user: userList2){
System.out.println("userList2 :" + user);
}
// 通过 name 模糊查询数据
List<User> userList3 = userService.findByNameLike("z");
System.out.println("findByNameLike () :" + userList3.size());
for (User user: userList3){
System.out.println("userList3 :" + user);
}
// 通过 id 列表查询数据
List<String> ids= new ArrayList<String>() ;
ids.add ("1") ;
ids.add ("2") ;
List<User> userList4 = userService.findByIdIn(ids) ;
System.out.println("findByIdIn () :" + userList4.size());
for (User user: userList4){
System.out.println("userList4 :" + user);
}
// 分页查询数据
PageRequest pageRequest = new PageRequest(0,10);
Page<User> userListS = userService.findAll(pageRequest);
System.out.println("findAll(pageRequest) :" + userListS.getContent().size());
for (User user: userListS.getContent()){
System.out.println("userListS :" + user);
}
// 新增数据
User user = new User();
user.setId("4");
user.setName ("test");
user.setPassword ("123456") ;
userService.save(user);
// 删除数据
userService.delete ("2");
}
运行结果: