JPA(Java Persistance API)是用于管理Java EE和Java SE环境中的持久化,以及对象、关系映射的Java API。实现该规范的常见的JPA框架有EclipseLink、Hibernate、Apache OpenJPA等。Spring Data JPA作为Spring Data家族的一部分,用于处理对基于JPA的数据访问层的增强支持。

​ Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,其主要目标是使对数据库的访问变得方便快捷,并支持MapReduce框架和云计算数据服务。Spring Data包含多个子项目:

  • Spring Data Common:提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化。
  • Spring Data JPA:简化创建JPA数据的访问层和跨存储的持久层功能
  • Spring Data Hadoop:基于Spring的Hadoop作业配置和一个POJO变成模型的MapReduce作业。
  • Spring Data Key Value:集成了Redis和Riak,提供多个常用场景下的简单封装。
  • Spring Data JDBC Extension:支持 Oracle RAD、高级消息队列和高级数据类型。

​ Spring Data JPA旨在通过将工作量减少到实际需要的量来显著改进数据访问层的实现。作为开发人员,只需要编写存储库的接口,包括自定义查询方法,而这些接口的实现,Spring Data JPA将会自动提供。

如何使用Spring Data JPA

​ 在配置文件中添加:

1
2
3
4
5
6
7
8
spring:
jap:
show-sql: ture
datasource: mysql
hibernate:
ddl-auto: update
properties:
hibernate: org.hibernate.dialect.MySQL57Dialect

​ ddl-auto: update 表示在项目启动时根据实体类更新数据库中的表(其他可选的值有create、create-drop、validate、no)

​ 创建实体类:

1
2
3
4
5
6
7
8
9
10
11
@Entity(name = "t_user")
public class user{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "user_name",nullable = false)
private String name;
@Transient
private String description;
//getter,setter
}

@Entity表示该类是一个实体类,在项目启动时会根据该类自动生成一张表,表的名称即@Entity注解中name的值,如果不配置name,默认表名为类名。

默认情况下,生成的表中的字段的名称就是实体类中属性的名称,通过@Column注解定制生成字段的属性,name表示该属性对应的数据表中字段的名称,nullable表示该字段非空

@Transient表示在生成表时,该属性被忽略,既不生成对应的字段。

dao层只需要继承Spring Data JPA的接口即可

1
2
3
public interface UserMapper extends JpaRepository<User,Long>{
List<User> findByNameLike(String name);
}

Spring Data JPA 的属性表达式

1
List<User> findByAddressZipCode(ZipCode zipcode);

​ 解析算法首先将AddressZipCode解释为属性,然后检查域类是否基于该属性名称,如果算法解析成功,则使用该属性。如果解析未成功,算法将继续解析最右侧的驼峰分割的单词,此时会先分为头部和尾部也就是AddressZipCode,并试图找到相应的属性。如果算法找到一个头部的属性,它讲从尾部那继续建立搜索树,按照刚刚描述的方法分割尾部。如果第一个分割不匹配,则算法将分割点移到左侧即AddressZipCode并继续上述算法。

​ 虽然这适用于大多数情况,但有时也可能会选择错误的属性,比如假设User类也有一个addressZip属性。该算法在第一个分割循环中匹配,并且选择错误的属性。要解决这种模糊性可以在方法名称中使用下划线_手动定义便利店。所以方法的名称为

1
List<User> findByAddress_ZipCode(ZipCode zipCdoe);

分页问题

​ 在需要分页和排序的时候可以使用Pageable和Sort来动态的对查询结果进行分页和排序

1
2
3
4
Page<User> findByLastname(String lastname,Pageable page);
Slice<User> findByLastname(String lastname,Pageable page);
List<User> findByLastname(String lastname,Sort sort);
List<User> findByLastname(Stirng lastname,Pageable page);

​ 第一个方法允许在查询方法的静态定义查询中通过org.springframework.data.domain.Pageable实例来动态的添加分页。分页类知道元素的总数和可用页数,它通过基础库来触发一个统计查询计算所有的总数。由于这个查询可能对存储库消耗巨大,可以使用Slice来代替。Slice仅仅知道是否有下一个Slice可用,这对查询大数据已经够了。

​ 排序选项与分页的处理方式一样,如果需要排序,简单的添加一个org.springframework.data.domain.Sort参数即可。正因如此,简单的返回一个列表也是可以的,在这种情况下,将不会构建实际页面实例所需要的附加元数据(这意味着将不必发出额外的计数查询),而是简单的限制查询,仅查找给定范围的实体。

限制查询结果

​ 查询方法可以通过关键字First和Top来限制,它们可以互换使用。可选的数字值可以追加到top/first,以指定要返回的最大结果的大小。如果缺省则假定结果大小为1

1
2
3
4
5
6
User findfirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname,Pageable pageable);
Page<User> findTop3ByLastname(String lastname,Pageable pageable);
List<User> findFirst10ByLastname(String lastname,Sort sort);
List<User> findTop10ByLastname(String lastname,Pageable,pageable);