Contents
  1. 1. jap 简介
  2. 2. jpa 发展
  3. 3. jpa 对象关系映射 ORM
  4. 4. jpa 实体
    1. 4.1. 实体属性
  5. 5. jpa创建实体
    1. 5.1. 常用注解
  6. 6. spring-data-jpa的使用
    1. 6.1. 简介
    2. 6.2. 基本查询
    3. 6.3. 预先生成方法
    4. 6.4. 自定义简单查询
    5. 6.5. 复杂查询
    6. 6.6. 分页查询
    7. 6.7. 自定义sql 查询
    8. 6.8. 多表查询
    9. 6.9. 多数据源的支持
      1. 6.9.1. 同源数据库的多源支持
    10. 6.10. 异构数据库多源支持
    11. 6.11. 其他
      1. 6.11.1. 使用枚举
    12. 6.12. spring data jpa 注解
    13. 6.13. spring data jpa的核心概念
    14. 6.14. spring data jpa @Query 定义中的SpEL的支持
      1. 6.14.1. 方法参数表达式
    15. 6.15. 高级表达式

jap 简介

1
2
java 持久层api是java 规范 用于在java 对象和数据库之间保存数据。 JPA充当面向对象领域和关系数据库之间的桥梁。
JPA 只是一个规范,它本身不执行任何操作。它需要一个实现。因此,像hibernate toplink ibatis 这样的工具具体实现了JPA数据持久性规范。

jpa 发展

  • 2006年 发布1.0版本
  • 2009年 发布2.0版本
  • 2013年 发布2.1版本
  • 2017年 作为开发维护开发而发布

jpa 对象关系映射 ORM

轻松处理各种数据库操作,如插入,更新,删除等。

jpa 实体

实体可以理解为java持久性库中定义的对象。

实体属性

  • 持久性:对象存储在数据库中并且可以随时访问。
  • 事务性:ACID
  • 粒度

jpa创建实体

常用注解

1
2
@Entity --标记这个类是一个实体,该注解必须放在类上
@Id -- 此注释位于持有持久标识属性的特定字段上。该字段被视为数据库中的主键。

spring-data-jpa的使用

简介

spring data jpa 是spring 基于ORM框架,JPA规范的基础上封装的一套jpa应用框架,用极简的代码即可实现对数据的访问和操作。极大的提高开发效率。

1
spring data jpa 让我们脱离Dao层操作,基本上所有的CRUD都可以依赖于它实现。

基本查询

基本查询分为两种,一种是spring data默认已经实现,一种是根据查询的方法来自动解析成SQL。

预先生成方法

spring data jpa 默认预先生成一些基本的CRUD的方法 继承JpaRepository

自定义简单查询

根据方法名来自动生成SQL:

自定义的简单查询就是根据方法名来自动生成SQL,主要的语法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟属性名称:

1
User findByUserName(String userName);

也使用一些加一些关键字AndOr

1
User findByUserNameOrEmail(String username, String email);

修改、删除、统计也是类似语法

1
2
3
Long deleteById(Long id);

Long countByUserName(String userName)

基本上SQL体系中的关键词都可以使用,例如:LIKEIgnoreCaseOrderBy

1
2
3
4
5
List<User> findByEmailLike(String email);

User findByUserNameIgnoreCase(String userName);

List<User> findByUserNameOrderByEmailDesc(String email);

复杂查询

特殊的方法或者自定义SQL

分页查询

spring data jpa 已经帮我们实现了分页的功能,在查询的方法中,需要传入参数Pageable

Pageable
,当查询中有多个参数的时候Pageable建议做为最后一个参数传入

1
2
3
Page<User> findALL(Pageable pageable);

Page<User> findByUserName(String userName,Pageable pageable);

Pageable 是spring封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void testPageQuery() throws Exception {
int page=1,size=10;
Sort sort = new Sort(Direction.DESC, "id");
Pageable pageable = new PageRequest(page, size, sort);
userRepository.findALL(pageable);
userRepository.findByUserName("testName", pageable);
}
限制查询

有时候我们只需要查询前N个元素,或者支取前一个实体。

ser findFirstByOrderByLastnameAsc();

User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);

自定义sql 查询

其实Spring data 觉大部分的SQL都可以根据方法名定义的方式来实现,但是由于某些原因我们想使用自定义的SQL来查询,spring data也是完美支持的;在SQL的查询方法上面使用@Query注解,如涉及到删除和修改在需要加上@Modifying.也可以根据需要添加 @Transactional 对事物的支持,查询超时的设置等

1
2
3
4
5
6
7
8
9
10
11
12
@Modifying
@Query("update User u set u.userName = ?1 where c.id = ?2")
int modifyByIdAndUserId(String userName, Long id);

@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteByUserId(Long id);

@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);

多表查询

​ 多表查询在spring data jpa中有两种实现方式,第一种是利用hibernate的级联查询来实现,第二种是创建一个结果集的接口来接收连表查询后的结果,这里主要第二种方式。

首先需要定义一个结果集的接口类。

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface HotelSummary {

City getCity();

String getName();

Double getAverageRating();

default Integer getAverageRatingRounded() {
return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
}

}

查询的方法返回类型设置为新创建的接口

1
2
3
4
5
6
7
@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
- "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);

@Query("select h.name as name, avg(r.rating) as averageRating "
- "from Hotel h left outer join h.reviews r group by h")
Page<HotelSummary> findByCity(Pageable pageable);

使用

1
2
3
4
Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0, 10, Direction.ASC, "name"));
for(HotelSummary summay:hotels){
System.out.println("Name" +summay.getName());
}

在运行中Spring会给接口(HotelSummary)自动生产一个代理类来接收返回的结果,代码汇总使用getXX的形式来获取

多数据源的支持

同源数据库的多源支持

日常使用分布式开发模式,不同的服务有不同的数据源,常常需要在一个项目中使用多个数据源,因此需要配置spring data jpa对多数据源的使用,一般分为三步:

  • 1 配置多数据源

  • 2 不同源的实体类放入不同包路径

  • 3 声明不同的包路径下使用不同的数据源、事务支持

    这里有一篇文章写的很清楚:Spring Boot多数据源配置与使用

异构数据库多源支持

比如我们的项目中,即需要对mysql的支持,也需要对mongodb的查询等。

实体类声明@Entity 关系型数据库支持类型、声明@Document 为mongodb支持类型,不同的数据源使用不同的实体就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface PersonRepository extends Repository<Person, Long> {

}

@Entity
public class Person {

}

interface UserRepository extends Repository<User, Long> {

}

@Document
public class User {

}

但是,如果User用户既使用mysql也使用mongodb呢,也可以做混合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
interface JpaPersonRepository extends Repository<Person, Long> {

}

interface MongoDBPersonRepository extends Repository<Person, Long> {

}

@Entity
@Document
public class Person {

}

也可以通过对不同的包路径进行声明,比如A包路径下使用mysql,B包路径下使用mongoDB

1
2
3
@EnableJpaRepositories(basePackages = "com.neo.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.neo.repositories.mongo")
interface Configuration { }

其他

使用枚举

使用枚举的时候,我们希望数据库中存储的是枚举对应的String类型,而不是枚举的索引值,需要在属性上面添加@Enumerated(EnumType.STRING) 注解

1
2
3
@Enumerated(EnumType.STRING) 
@Column(nullable = true)
private UserType type;

不需要和数据库映射的属性

正常情况下我们在实体类上加入注解@Entity,就会让实体类和表相关连如果其中某个属性我们不需要和数据库来关联只是在展示的时候做计算,只需要加上@Transient属性既可。

1
2
@Transient
private String userName;

[spring data jap 参考手册](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/)

spring data jpa 注解

Springboot jpa提供了自动填充这两个字段的功能,简单配置一下即可。@CreatedDate、@LastModifiedDate@CreatedBy、`@LastModifiedBy`前两个注解就是起这个作用的,后两个是设置修改人和创建人的,这里先不讨论。

@Version注解表示对表添加乐观锁定的支持。

@Modifying 完成修改操作不支持新增操作

@DynamicUpdate 是否自动更新

spring data jpa的核心概念

springdata的核心接口是Repository。使用domian类去管理。

spring data jpa @Query 定义中的SpEL的支持

Spring Data JPA允许使用@Query注释手动定义要由存储库方法执行的查询。不幸的是,JPQL中的参数绑定非常有限,只允许您设置一个值并提供一些类型转换。Evans版本系列的最新Spring Data JPA M1版本通过添加
对使用SpEL表达式的支持来缓解这种痛苦,以便在@Query注释中的语句中使用动态绑定参数,这在手动定义查询时提供了额外的灵活性。

方法参数表达式

SpEL支持提供对查询方法参数的访问

1
2
@Query("select u from User u where u.firstname = :#{#customer.firstname}")
List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer)

高级表达式

可以引用spring security 进行安全验证,如查询限制仅返回与当前经过身份验证的相关用户信息。

1
2
Query("select u from User u where u.emailAddress = ?#{principal.emailAddress}")
List<User> findCurrentUserWithCustomQuery();

如您所见,我们引用了Spring Security的属性principal。那么Spring Data SpEL如何支持与Spring Security集成。

1547115370479