Spring Data Jpa 入门

介绍:

Spring Data JPA为Java Persistence API(JPA)提供了存储库支持。它简化了需要访问JPA数据源的应用程序的开发。

核心概念:

The central interface in the Spring Data repository abstraction is Repository.

CrudRepository接口,提供crud方法。

 

PagingAndSortingRepository接口,提供分页查询方法。

JpaRepository在CrudRepository和PagingAndSortingRepository上扩展更多抽象方法。

查询方法:

1)设计实体Entity

@Entity(name = "admin")
@Getter
@Setter
public class Admin implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String account;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private short status;

    @Column(name = "create_time")
    @CreationTimestamp
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date createTime;

    @Column(name = "update_time")
    @UpdateTimestamp
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date updateTime;

    @Column(name = "login_failure_num")
    private short loginFailureNum;

    @Column
    private String address;

    @Column
    private String latitude;

    @Column
    private String longitude;

    @Column
    private String phone;

}

2) 设计仓库repository

@Repository
public interface AdminRepository extends CrudRepository<Admin, Long> {

    Page<Admin> findAll(Pageable pageable);

    Optional<Admin> findById(Long id);

    void deleteById(Long id);

    @Query(value = "select a.* from admin a where a.address= :address and a.account= :account",
            countQuery = "select count(*) from admin a where a.address= :address and a.account= :account",
            nativeQuery = true
    )
    Page<Admin> searchData(@Param("address") String address, @Param("account") String account, Pageable pageable);

    @Query("select a from admin a where a.name = :name or a.account = :account")
    List<Admin> searchData2(@Param("name") String name, @Param("account") String account, Pageable pageable);

}

3)查询方式:

3.1)内置jpa查询构造器:分为主语和谓语(find…Byexists…By),主谓之间除了(Distinct和Top/First)之外的都当成描述信息。

 3.2)注解查询:@Query,可以自定义SQL语句,通过设置nativeQuery=true。

4)排序:

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.lastname like ?1%")
  List<User> findByAndSort(String lastname, Sort sort);

  @Query("select u.id, LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%")
  List<Object[]> findByAsArrayAndSort(String lastname, Sort sort);
}

repo.findByAndSort("lannister", Sort.by("firstname"));                (1)
repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)")); (2)
repo.findByAsArrayAndSort("bolton", Sort.by("fn_len"));               (3)

5)限制:

User findFirstByOrderByLastnameAsc();//order by lastname asc limit 1

User findTopByOrderByAgeDesc();//order by age desc limit 1

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);//where lastname=:lastname limit 10

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);// where lastname=:lastname limit 0,3

List<User> findFirst10ByLastname(String lastname, Sort sort);//where lastname=:lastname limit 0,10

List<User> findTop10ByLastname(String lastname, Pageable pageable);// wehre lastname=:lastname limit 0,10

6)联结(多表查询)

6.1) 一对一(one-to-one):

每个实体实例都与另一个实体的单个实例相关。例如,为了对每个存储仓都包含一个小部件的物理仓库进行建模,StorageBin和widget将具有一对一的关系。一对一关系在相应的持久属性或字段上使用javax.persistence.OneToOne注释。

@OneToOne
@JoinColumn(name = "外键", referencedColumnName = "外键对应的主键")
private Object role;

6.2)一对多(one-to-many):

一个实体实例可以与其他实体的多个实例相关。例如,一个销售订单可以有多个行项目。在订单应用程序中,order将与LineItem具有一对多关系。一对多关系在相应的持久属性或字段上使用javax.persistence.OneToMany注释。

@OneToMany(mappedBy = "联结字段", fetch = FetchType.EAGER)
private Set<Admin> admins;

6.3) 多对一(many-to-one):

一个实体的多个实例可以与另一实体的单个实例相关。这种多样性与一对多关系相反。在刚才提到的例子中,从LineItem的角度来看,与Order的关系是多对一的。多对一关系在相应的持久属性或字段上使用javax.persistence.ManyToOne注释

@ManyToOne
@JoinColumn(name="role_id")
private AdminRole role;

6.4)多对多(many-to-many):

实体实例可以相互关联。例如,在大学里,每门课程都有很多学生,每个学生可以选修几门课程。因此,在注册申请中,课程和学生将具有多对多关系。多对多关系对相应的持久属性或字段使用 javax.persistence.ManyToMany 注释。

主表
@ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "中间表", joinColumns = @JoinColumn(name = "外键", referencedColumnName = "主键"), inverseJoinColumns = @JoinColumn(name = "外键", referencedColumnName = "主键"))
private List<Object> menus;
附表
@ManyToMany(mappedBy = "menus", fetch = FetchType.EAGER) private Set<Object> adminRoles;

问题:

1)一个实体内出现两个以上List类型集合关系查询,会导致异常org.hibernate.loader.MultipleBagFetchException。

2)关联查询时出现N+1问题,导致循环查询。解决:@NamedEntityGraph和@EntityGraph

3)出现查询数据流水异常(javax.persistence.EntityNotFoundException)。解决:@NotFound(action=NotFoundAction.IGNORE)。

posted @ 2024-02-07 17:26  TongXiaLi  阅读(8)  评论(0编辑  收藏  举报