一、JPA、Hibernate、Spring Data JPA 的区别与联系
1、什么是 JPA, 它与Hibernate有什么关系?
JPA(Java Persistence API):是Java EE 5的标准ORM接口,也是ejb3规范的一部分。可以通过注解或者XML描述【对象-关系表】之间的映射关系,并将实体对象持久化到数据库中。
JPA为我们提供了以下功能:
- ORM映射元数据:JPA支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中。
如:@Entity、@Table、@Column、@Transient等注解。
- JPA 的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
如:entityManager.merge(T t)。
- JPQL查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。
如:from Student s where s.name = ?
但是:
JPA仅仅是一种规范,也就是说JPA仅仅定义了一些接口,而接口是需要实现才能工作的。所以底层需要某种实现,而Hibernate就是实现了JPA接口的ORM框架。
也就是说:
JPA是一套ORM规范,Hibernate实现了JPA规范。
Hibernate主要是通过三个组件来实现:
- hibernate-core:Hibernate的核心实现,提供了Hibernate所有的核心功能。
- hibernate-entitymanager:Hibernate实现了标准的JPA,可以把它看成hibernate-core和JPA之间的适配器,它并不直接提供ORM的功能,而是对hibernate-core进行封装,使得Hibernate符合JPA的规范。
- hibernate-annotation:Hibernate支持annotation方式配置的基础,它包括了标准的JPA annotation以及Hibernate自身特殊功能的annotation。
2、什么是Spring Data JPA?
Spring Data JPA 是Spring 提供的一套简化JPA 开发的框架,按照约定好的【方法命名规则】写dao层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作。同时提供了很多除了CRUD 之外的功能,如分页、排序、复杂查询等。
Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的技术实现。如图:
3、Spring Data JPA 相关接口:
- Repository:仅仅只是一个标识,没有任何方法,方便Spring自动扫描识别
- CrudRepository:继承Repository,实现一组CRUD相关方法
- PagingAndStortingRepository:继承CrudRepository,实现一组分页排序相关方法
- JpaRepository:继承PagingAndStortingRepository,实现一组JPA规范方法
4、Spring Data JPA 自定义接口约定命名规则:
关键字 | 例子 | 对应的JPQL语句 |
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase |
5、Spring JPA自定义接口解析步骤:
在进行方法名解析时会先去掉多余的前缀,比如find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析,并且如果方法最后一个参数时 Sort 或 Pageable 类型,也会提取相关信息。
比如:findByNameLikeAndAgeGreaterThan
- 剔除findBy
- 判断nameLikeAndAgeGreaterThan(根据POJO规范,首字母变小写)是否为返回对象 User 的一个属性,如果是,则根据该属性进行查询,如果没有该属性,则进行下一步
- 从右往左截取第一个大写字母开头的字符串(此处为Than),然后检查剩下的字符串是否为 User 的一个属性,如果是,则根据该属性进行查询,否则重复第2步,直到找出 name 为 User 的属性
- 从已截取的部分后面开始,重新第 1 步开始(剔除条件语句),循环,直到把方法名处理完毕
- 通过获取的操作、条件和属性、带入参数值,生成查询。
二、Spring JPA 配置项
在SpringBoot中,Hibernate的相关配置都保存在HibernateProperties,它配置了ConfigurationProperties注解,会自动装载前缀为spring.jpa.hibernate的配置。
1、常用配置项
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
# 是否开启JPA Repositories,缺省: true
spring.data.jpa.repositories.enabled=true
# JPA数据库类型,默认可以自动检测,也能通过设置spring.jpa.database-platform达到同样效果
spring.jpa.database=ORACLE
# 数据库平台,常见的值如:
# org.hibernate.dialect.Oracle10gDialect
# org.hibernate.dialect.MySQL5InnoDBDialect
#下文有详细介绍
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
# 是否使用JPA初始化数据库,可以在启动时生成DDL创建数据库表,缺省为false
spring.jpa.generate-ddl = false
# 更细粒度的控制JPA初始化数据库特性,用来设定启动时DDL操作的类型,下文有详细介绍
# 内嵌数据库 hsqldb, h2, derby的缺省值为create-drop
# 非内嵌数据库的缺省值为none
spring.jpa.hibernate.ddl-auto = update
# Hibernate操作时显示真实的SQL, 缺省:false
spring.jpa.show-sql = true
# Hibernate 5 隐含命名策略类的全限定名
spring.jpa.hibernate.naming.implicit-strategy= org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl
# Hibernate 5 物理命名策略类的全限定名
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE.
spring.jpa.hibernate.use-new-id-generator-mappings=
# 额外设置JPA配置属性,通常配置项是特定实现支持的,如Hibernate常有下面的几条配置项
spring.jpa.properties.* =
# 将SQL中的标识符(表名,列名等)全部使用引号括起来
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
# 日志记录执行的SQL
spring.jpa.properties.hibernate.show_sql = true
# 是否将格式化SQL日志
spring.jpa.properties.hibernate.format_sql = true
# 是否注册OpenEntityManagerInViewInterceptor. 绑定JPA EntityManager 到请求线程中. 默认为: true.
spring.jpa.open-in-view=true