(三)Spring Boot 集成 Spring Data JPA —— 《一步一步学 Spring Boot 2》读书笔记

本文纯个人读书笔记,书籍《一步一步学 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");
    }

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值