《Spring Data Jpa从入门到精通》知识点总结

以下内容纯属个人扯淡,仅供参考,建议拜读原著

目录

读后感

2020/8/18

第一部分:基础

第1章:整体认识JPA

第2章:JPA基础查询方法

第3章:定义查询方法

第4章:注解式查询方法

第5章:@Entity实例中常用注解详解

第二部分:高级

第6章:JpaRepository扩展详解

第7章:Spring Data JPA的扩展

第8章:DataSource的配置

第三部分:扩展

第9章:IDEA与Spring JPA

第10章:Spring Data Redis 详解

第11章:SpEL详解

第12章:Spring Data REST

附录

附录1:Repository Query Method 关键字列表

附录2:Repository Query Method 返回值类型

附录3:JPA注解大全

附录4:Spring中涉及的注解

附录5:application.properties中关于JPA的配置大全


 

读后感

2020/8/18

个人感觉这本书很不好。

第1:书名是:SpringDataJpa从入门到精通,作为工具书关于SpringDataJpa的广度又不够,深度方面更加是浅的离谱,其他的实战类的书是点到为止,但这里是点都不全。有关广度这个问题,书里又花了将近一半的文字在讲其他内容:SpringData、SpringDataRedis、SpEL表达式等,甚至IDEA部分的图片和描述占据了很大篇幅。

第2:之前看Spring实战,各个章节分的很清楚,而且基本整体都是总-分结构,先整体结构再局部描述。而这本书说实话章节安排有些乱

第3:博客有错别字我能理解,书上有些地方有错别字,而且有些地方行文逻辑都是难以看懂。例如下面这句话,逗号前一句和逗号后一句话,这两句话逻辑是这样:可以通过......。要创建.....

第4:书的文字部分,有些感觉是东拼西凑来的,所以总是读的一段一段,思路跳跃的厉害

总之一句话:看的很难受。所以,本人只是看了2-7章,个人观点,不喜勿喷。

倒不如参考一篇博客:Spring data jpa 复杂动态查询方式总结、QueryDSL:使用QueryDSL

这篇博客开篇就说:不太推荐使用jpa做ORM框架,因为对于复杂查询时是不太灵活的,而是建议使用mybatis框架自己写sql,jpa对于简单查询是十分方便的。
1、核心方法
    查询所有数据 findAll()
    修改 添加数据  S save(S entity)
    分页查询 Page<S> findAll(Example<S> example, Pageable pageable)
    根据id查询 findOne()
    根据实体类属性查询: findByProperty (type Property); 例如:findByAge(int age)
    删除 void delete(T entity)
    计数 查询 long count() 或者 根据某个属性的值查询总数 countByAge(int age)
    是否存在   boolean existsById(ID primaryKey)

2、查询关键字(方法命名方式)
    
3、注解
    @Modifying、@Query、@Transaction、@Async

4、继承JpaSpecificationExecutor接口进行复杂查询
    可以实现多条件分页

5、引入QueryDSL
    QueryDSL是基于各种ORM框架以及SQL之上的一个通用API的查询框架

第一部分:基础

第1章:整体认识JPA

概览

ORM框架对比
JPA规范
SpringData项目
SpringDataJPA
MySQL快速开发实例

1、ORM框架对比

1、MyBatis
    侧重于POJO与SQL之间的映射关系,可以进行更为细致的SQL,目前占有率最高,上手容易,适合互联网应用公司开发API场景
2、Hibernate
    侧重于对象与对象之间的关系
    对JDBC进行了非常轻量级的对象封装。有自己的HQL查询语言,数据库移植性很好
    符合JPA规范,上手难,适合企业级应用系统开发
3、Spring Data JPA
    JPA规范的再次封装,底层使用Hibernate+JPA实现
    引用JPQL查询语言,属于Spring生态一部分
    上手简单

2、JPA规范

全称Java Persistence API(Java持久层API),是JDK5.0注解/xml描述对象关系表的映射关系(关系型数据库),并将运行期实体对象持久化到数据库中,Sun引入JPA规范的原因:简化现有JavaEE和JavaSE应用开发;整合ORM技术,实现大一统(mybatis不符合JPA规范)。其内容包括3个部分:

1、一套API标准
    在javax.persistence包下
    用于操作实体对象,执行CRUD操作
2、面向对象查询语言(JPQL)
    避免程序的SQL紧密耦合
3、ORM元数据的映射
    JPA支持xml、注解两种元数据的方式(元数据描述着对象和表之间的映射关系)

3、SpringData项目

致力于提供一个一致的、基于Spring的数据访问编程模型,支持关系数据库、NoSQL、基于云的数据服务。SpringDataCommon是所有模块的公有部分,它提供了技术中立的库接口、一个坚持Java类的元数据模型,它的子项目有:

主要子项目:Commons、Gemfire、JPA、KeyValue、LDAP、MongoDB、REST、Redis、Apache Cassandra、Apache Solr
社区支持的子项目:Aerospike、Couchbase、DynamoDB、Elasticsearch、Hazelcast、Jest、Neo4j、Vault、JDBC Extensions、Hadoop、Spring Content

4、SpringDataJPA

主要类

7个Repository接口
    Repository
    CrudRepository
    PagingAndSortingRepository
    QueryByExampleExecutor
    JpaRepository
    JpaSpecificationExecutor
    QueryDslPredicateExecutor
2个实现类
    SimpleJpaRepository
    QueryDslJpaRepository
JPA底层封装类
    EntityManager(javax.persistence)
    EntityManagerImpl(org.hibernate.jpa.internal)

类结构

5、MySQL快速开发实例

(1)环境要求:JDK1.8+、Maven3.0+、IDEA

(2)数据库及表

数据库名=db_example,表名=user

CREATE TABLE `user` {
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(50) DEFAULT NULL,
    `email` varchar(200) DEFAULT NULL,
    PRIMARY KEY ('id')
}

(3)创建项目

IDEA中的Spring Initializr创建,选择Web、JPA、MySQL模块

(4)application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/db_example
spring.datasource.username=xxxx
spring.datasource.password=xxxx

(5)创建User实体

@Entity
public class User {

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

    private String name;

    private String email;

    getter/setter
}

(6)UserRepository

public class UserRepository extends CrudRepository<User,Long> {
}

(7)UserController

@Controller
@RequestMapping(path = "/demo")
public class UserController{
    
    @Autowired
    private UserRepository userRepository;

    @GetMapping("/add")
    public void addUser( @RequestParam String name, @RequestParam String email ){
        User n = new User();
        n.setName(name);
        n.setEmail (email);
        userRepository.save(n);
    }

    @GetMapping("/all")
    public Iterable<User> getAllUsers(){
        return userRepository.findAll();
    }
}

 

第2章:JPA基础查询方法

概览

Repository概述
分析方法
核心类分析
    CrudRepository

总结:主要是记住Repository等这些接口之间的关系和和api概览;实际上使用时是使用SimpleJpaRepository。但有个疑问:如果我们程序中新建接口直接继承CrudRepository,框架通过动态代理生成对象,但貌似生成对象实例却是SimpleJpaRepository呢?

疑问:NoRepositoryBean、QueryByExampleExecutor两个类的分析呢?

1、Repository概述

      该接口位于Spring Data Common/lib中,是Spring Data做数据库操作最底层的抽象接口、最顶级的父类。该接口为空接口,仅仅作为一个标识作用(用于捕获要使用的类型,用户也可以扩展此接口,Spring底层做动态代理时就会发现:只要是它的子类,就都代表存储库操作)。该泛型接口的类型参数:T是领域类,ID是该领域类的id

public interface Repository<T, ID extends Serializable> {
}

2、分析方法

1》查看类的继承结构

打开Repository.class类,Navigate/Type Hierarchy(快捷键:Ctrl + H)。注意:要找到最顶层的父级接口,向下级分析

Repository
    RevisionRepository
    ReactiveCrudRepository
        ReactiveSortingRepository
    RxJava2CrudRepository
        RxJava2SortingRepository
    CrudRepository
        PagingAndSortingRepository
            KeyValueRepository
                SimpleKeyValueRepository
                    QuerydslKeyValueRepository(+QuerydslPredicateExecutor)
            JpaRepository(+QueryByExampleExecutor)
                JpaRepositoryImplementation(JpaSpecificationExecutor)
                    SimpleJpaRepository
                        QuerydslJpaRepository(+QuerydslPredicateExecutor)
                

2》查看类的UML关系

打开某个类(一般是较低级的具体实现类),右键/Show Diagrams(快捷键:Ctrl+Shift+Alt+U)。me:打开QueryDslJpaRepository,如下:

7个Repository接口,2个实现类(SimpleJpaRepository、QueryDslJpaRepository)

注意:选中某个类F4,可以查看该类源码

参考:idea中的Diagram功能,查看类图

3》查看类成员

快捷键:Ctrl+F12是简单弹框版,Alt+7是打开File Structure。功能是一样的(勾选左上角选项,可以看到继承下来的成员)

3、核心类分析

1》CrudRepository

package org.springframework.data.repository;


@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

        //有2句sql:第1句查询该实体是否存在;第2句是新增/更新
        //判断是否存在有两种机制:根据主键判断;根据Version判断
	<S extends T> S save(S entity); 
        
        //批量保存。for循环上一个方法
	<S extends T> Iterable<S> saveAll(Iterable<S> entities);
        
        //根据主键查询
	Optional<T> findById(ID id);

        //根据主键判断是否存在
	boolean existsById(ID id);

	Iterable<T> findAll();

	Iterable<T> findAllById(Iterable<ID> ids);

	long count();

        //这里也会先查询是否存在
	void deleteById(ID id);

	void delete(T entity);

	void deleteAll(Iterable<? extends T> entities);

	void deleteAll();
}

该接口提供公共的基本CRUD方法。默认提供一个具体实现类SimpleJpaRepository

问题:Java多态。我们如果用一个接口,如:AbcRepository接口去直接继承CrudRepository接口,那么AbcRepository.save()实际使用的是SimpleJpaRepository?报错:ITestB it = new TestA(),因为类TestA并不是ITestB接口的子类

public interface ITest {
    void test();
}

public class TestA implements ITest {

    @Override
    public void test() {
        System.out.println("撒老大看见");
    }
}

public interface ITestB extends ITest {

}

2》PagingAndSortingRepository

@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
	
    Iterable<T> findAll(Sort sort);
    
    Page<T> findAll(Pageable pageable);
}

总结:该接口再CrudRepository的基础上增加了排序、分页功能

3》JpaRepository

上述1》、2》类是在spring-data-commons包中,是为了兼容NoSQL而进行了一些抽象封装。从该接口这层往下是对关系型数据库进行抽象封装,它继承了PagingAndSortingRepository,实现类仍然是SimpleJpaRepository,除此之外还继承了QueryByExampleExecutor接口。它在1》、2》的基础上多了QueryByExample条件查询、批量查询的返回类型不再是Iterator而是List

package org.springframework.data.jpa.repository;

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
	List<T> findAll();

	List<T> findAll(Sort sort);

	List<T> findAllById(Iterable<ID> ids);

	<S extends T> List<S> saveAll(Iterable<S> entities);
	void flush();

	<S extends T> S saveAndFlush(S entity);

	void deleteInBatch(Iterable<T> entities);

	void deleteAllInBatch();

	T getOne(ID id);

	@Override
	<S extends T> List<S> findAll(Example<S> example);

	@Override
	<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

4》SimpleJpaRepository

该类是JPA整个数据库相关Repository的接口实现类,可以继承该类进行扩展(如:JPA提供的QueryDsl)。该类也是Spring动态代理的实现类。通过EntityManager进行实体操作,JpaEntityInForMation保存了实体的相关信息及crud方法元数据

第3章:定义查询方法(方法命名方式)

总结:本章主要是利用方法名来定义查询方法,SpringDataJpa将根据方法名构造出查询。由于Spring JPA Repository是采用动态代理机制,因此这里有2种定义查询方法:

1、从方法名称中可以指定特定用于存储的查询和更新(第3章/本章);
    本人后面统一称之为:方法命名方式
2、通过使用@Query手动定义(第4章)
    本人后面统一称之为:注解声明方式

1、定义查询方法的配置方法

 

2、设置查询策略

在SpringBoot启动类上来设置:

@EnableJpaRepositoies(queryLookupStrategy=QueryLookupStrategy.CREATE_IF_NOT_FOUND)
(SpringBoot启动类)

CREATE:
    直接根据方法名进行创建(即:只限于方法命名方式)
    规则:根据方法名称的构造进行尝试
        从方法名中删除给定的一组已知前缀,并解析该方法的其余部分
        若方法名不符合规则,则应用启动会报错
USE_DECLARED_QUERY:
    声明式创建(第4章)(即:只限于注解声明方式)
    启动时会尝试找到一个声明的查询,若没找到则抛异常
    查询可以由某处注释或其他方法声明
CREATE_IF_NOT_FOUND:
    默认值
    上述两方法结合:先用声明式查找,若失败则尝试根据方法名创建

结论:默认就是2种方式结合。优先级是先注解再方法名,下面是一些具体策略类的关系:

3、方法命名方式

框架中有个根据方法名的查询生成器机制。一般用于:对于实体类型上构建约束查询(对实体单表的约束查询),其规则如下

1、查询策略关键字
2、查询字段
3、限制性条件

1》基本使用

interface PersonRepository extends Repository<User, Long> {

    //where emailAddress=? and lastname=?
    List<User> findByEmailAddressAndLastname(EmailAddress emailAddress,String lastname);

    //where lastname=? or firstname=?,并去重
    List<User> findDistinctPeopleByLastnameOrFirstname(String lastname,String firstname);
    List<User> findPeopleDistinctByLastnameOrFirstname(String lastname,String firstname);

    //where lastname(忽略大小写)=?
    List<User> findByLastnameIgnoreCase(String lastname);
    //where lastname(忽略大小写)=? and firstname(忽略大小写)=?
    List<User> findByLastnameAndFirstnameAllIgnoreCase(String lastname,String firstname);

    //where lastname=? ,并根据firstname排序(Asc、Desc)
    List<User> findByLastnameOrderByFirstnameAsc(String lastname,String firstname);
}

解析方法的实际结果取决于创建查询方法的持久性存储。注意事项

1、表达式通常是可以连接的运算符的属性遍历
    可以使用组合属性表达式:AND、OR
    也可以将运算关键字Between、LessThan、GreaterThan、Like作为属性表达式
    受支持的操作元可能因数据存储而已(参考官方文档)

2、该方法解析器支持设置一个IgnoreCase标识个别特性,例如:
    findByLastnameIgnoreCase、findByLastnameAndFirstnameAllIgnoreCase支持忽略大小写
    受支持的操作元可能因数据存储而已(参考官方文档)

3、可通过OrderBy在引用属性和提供排序方向的查询方法中,附加一个子句来应用静态排序

2》关键字列表

关键字方式1:方法命名

方式2:注解声明。@Query(见第4章)

对应的JPQL表达示例

x表示映射到表的类对象

And

Or

findByLastnameAndFirstname

findByLastnameOrFirstname

where x.lastname = ?1 and x.firstname = ?2

where x.lastname = ?1 or x.firstname = ?2

Is、Equals

Not

findByFirstname

findByFirstnameIs

findByFirstnameEquals

findByFirstnameNot

where x.firstname = ?1

where x.firstname <> ?1

LessThan

LessThanEqual

GreaterThan

GreaterThanEqual

findByAgeLessThanEqualwhere x.age <= ?1
BetweenfindByStartDateBetweenwhere x.startDate between ?1 and ?2

After

Before

findByStartDateAfterwhere x.startDate > ?1

IsNull

IsNotNull、NotNull

findByAgeIsNullwhere x.age is null

Like

NotLike

StartingWith

EndingWith

Containing

findByFirstnameLike

均添加在末尾

where x.firstname like ?1

not like ?1

like %?1

like ?1%

like %?1%

OrderByfindByAgeOrderByLastnameDescwhere x.age = ?1 order by lastname desc

In

NotIn

findByAgeIn(Collection<Age> ages)where x.age in ?1

True

False

fingByActiveTruewhere x.active = true
IgnoreCasefindByFirstnameIgnoreCasewhere UPPER(x.firstname) = UPPER(?1)

注意:除了find关键字外,查看PartTree还有以下关键字,并有相应的返回类型

1、Query_PATTERN:find、read、get、query、stream
    返回类型为List<T>

2、COUNT_PATTERN:count
    long

3、EXISTS_PATTERN:exists
    boolean

4、DELETE_PATTERN:delete、remove
    List<T>

3》方法查询策略中的属性表达式

 

 

4、查询结果的处理

 

5、实现机制介绍

TODO:看一下相关的源码

 

 

第4章:注解式查询方法(注解声明方式)

概览

@Query
@Param
SpEL表达式的支持
@Modifying(修改查询)
@QueryHints(Query优化)
@Procedure(存储过程的查询方法)
@NamedQueries(预定义查询)

1、@Query

源码


public @interface Query {

    //指定JPQL的查询语句。(nativeQuery=true 的时候,是原生的SQL语句)
    String value() default "";


    //指定count的JPQL语句,如果不指定将根据query自动生成。(nativeQuery=true,原生的SQL语句)
    String countQuery() default "";
 
    //根据哪个字段来count,一般默认即可。
    String countProjection() default "";

    //默认是false,表示value里面是不是原生的Sql语句
    boolean nativeQuery() default false;

    //可以指定一个query的名字,必须是唯一的。如果不指定,默认的生成规则是:
    //{SdomainClass}.${queryMethodName}
    String name() default "";

    //可以指定一个count的query 名字,必须是唯一的。如果不指定,默认的生成规则是:
    //{SdomainClass}.${queryMethodName}.count
    String countName() default "";
}

1》简单CRUD

public interface UserRepository extends JpaRepository<User, Long> {
}

1)条件查询

@Query("select u from User u where u.email = ?1")
User findByEmail(String email);

注意:1)、2)中是JPQL语言,因此是类名User、属性名email,而不是数据表名、字段名

2)like模糊

@Query("select u from User u where u.name like%?1")
List<User> findByFirstnameEndsWith(String name);

注意:需要手动加上%,模糊查询的符号

3)原始SQL

@Query(value="select * from user where email = ?1",nativeQuery=true)
User findByEmail(String email);

4)原始SQL+排序

@Query(value="select * from user_info where first_name=?1 order by ?2",nativeQuery=true)
List<UserInfoEntity> findByFirstName(String firstNanme,String sort);

注意:nativeQuery是不支持Sort的参数查询,因此上述方法第2个参数是String类型而不是Sort类型,并且使用时传入的是数据库表的字段名而不是对象的属性名,如,根据last_name字段排序:

repository.findByFirstName("jack","last_name"); 

2》排序

@Query在JPQL下实现排序,直接使用PageRequestSort参数即可

1、
@Query(value="select u from User u where u.lastname like ?1%")
List<UserInfoEntity> findByAndSort(String lastnanme,Sort sort);
调用示例:
repo.findByAndSort("lannister",new Sort("firstname"));
repo.findByAndSort("stark",new Sort("LENGTH(firstname)"));
repo.findByAndSort("targaryen",JpaSort.unsafe("LENGTH(firstname)"));

2、
@Query(value="select u。id,LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%")
List<Object[]> findByAsArrayAndSort(String lastnanme,Sort sort);
调用示例:
repo.findByAsArrayAndSort("bolton",new Sort("fn_len"));

疑问:这里代码没看懂,是想完成什么业务?

3》分页

1、
@Query(value="select u from User u where u.lastname like ?1%")
List<UserInfoEntity> findByAndSort(String lastnanme,Sort sort);
调用示例:
repo.findByAndSort("lannister",new Sort("firstname"));
repo.findByAndSort("stark",new Sort("LENGTH(firstname)"));
repo.findByAndSort("targaryen",JpaSort.unsafe("LENGTH(firstname)"));

2、
@Query(value="select u。id,LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%")
List<Object[]> findByAsArrayAndSort(String lastnanme,Sort sort);
调用示例:
repo.findByAsArrayAndSort("bolton",new Sort("fn_len"));

2、@Param

3、SpEL表达式的支持

4、@Modifying(修改查询)

5、@QueryHints(Query优化)

6、@Procedure(存储过程的查询方法)

7、@NamedQueries(预定义查询)

第5章:@Entity实例中常用注解详解

概览

javax.persistence
基本注解
    @Entity
    @Table
    @Id
    @IdClass
    @GeneratedValue
    @Basic
    @Transient
    @Column
    @Temporal
    @Enumerated
    @Lob
关联关系注解
    @JoinColumn
    @OneToOne
    @OneToMany、@ManyToOne
    @OrderBy
    @JoinTable
    @ManyToMany
其他:
    left join、inner join
    @EntityGraph

1、javax.persistence

2、基本注解

3、关联关系注解

4、其他

第二部分:高级

第6章:JpaRepository扩展详解

1、QueryByExampleExecutor

 

2、JpaSpecificationExecutor

 

3、自定义Repository

 

第7章:Spring Data JPA的扩展

 

 

 

第8章:DataSource的配置

1、默认DataSource

2、Ali Druid DataSource

3、事务

4、配置多数据源

5、Naming命名策略

第三部分:扩展

第9章:IDEA与Spring JPA

第10章:Spring Data Redis 详解

第11章:SpEL详解

第12章:Spring Data REST

附录

附录1:Repository Query Method 关键字列表

附录2:Repository Query Method 返回值类型

附录3:JPA注解大全

附录4:Spring中涉及的注解

附录5:application.properties中关于JPA的配置大全

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值