一、Spring data jpa介绍
一、Spring data jpa介绍
引自
Spring Data JPA Tutorial: Introduction(https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-introduction/)
正文
通常来说,我们使用JPA去实现我们的DAO(data access object)层,需要花费大量的时间,一般而言,我们会使用下面的步骤:
- 创建一个抽象的DAO类,去提供针对entity的通用CRUD操作,这个类在我的项目里通常被叫做BaseDao、AbstractDAO偶尔也被叫做CommonDao。
- 创建一个具体的实现类,去继承这个抽象的DAO类,然后编写具体的行为。
大概的实现方式如下:
- BaseDao 接口定义
- BaseDao Hibernate抽象实现类
- 某业务Dao的接口定义
- 某业务Dao的接口实现
/** * BaseDao接口设计 * @param <T> 类 * @param <PK> 主键类型 * @Author Tan * @DATE 17-4-21 下午9:10 */ public interface BaseDao<T,PK> { //添加 void add(T t); //删除 void delete(T t); //更新 void update(T t); //根据id查询 T findOne(PK id); //查询所有 List<T> findAll(); } /** * BaseDao Hibernate实现,删除了部分代码 * @param <T> 类 * @param <PK> 主键类型 * @Author Tan * @DATE 17-4-21 下午9:10 */ public abstract class BaseDaoImpl<T,PK> extends HibernateDaoSupport implements BaseDao<T,PK> { //添加 public void add(T t){ this.getHibernateTemplate().save(t); } //删除 public void delete(T t){ this.getHibernateTemplate().delete(t); } //更新 public void update(T t){ this.getHibernateTemplate().update(t); } //根据id查询 public T findOne(PK id){ return (T)this.getHibernateTemplate().get(clazzP, id); } //查询所有 public List<T> findAll(){ return (List<T>) this.getHibernateTemplate().find("from "+clazzP.getSimpleName()); } } /** * Student的Dao设计 * @Author Tan * @DATE 17-4-21 下午9:27 */ public interface StudentDao extends BaseDao<Student,Long> { } /** * Student的具体Dao实现 * @Author Tan * @DATE 17-4-21 下午9:29 */ public class StudentDaoImpl extends BaseDaoImpl<Long> implements StudentDao { }
说实话,这样很麻烦,我们依然要写很多代码去实现我们的数据库查询和调用。更坑爹的是,每次我们在创建新的数据库查询的时候,我们都不得不干一遍上面的事情,太浪费时间了。
实际上,在我以前经历的某个项目的框架中,按照上面的思路,做了进一步的优化,就是实现一个通用Dao。大致的思路是在上述的BaseDao中追加对于Hql和Sql的支持,不使用范型,id的生成策略写死成UUID。然后我们就有了一个真正意义上万能的通用DAO。在那个项目中,Dao层完全被这一个CommonDao给代替了。所以,不妨设想一下,我们当时遇到了什么问题?
这篇文章会介绍什么是Spring-data-jpa,我们将了解这到底是个什么,并且将理顺一下Spring data的repository的接口。
题外话:前文说了,spring data jpa是为了解决传统DAO层的问题,他们为这种强壮的DAO层命名为repository,令我们困惑的是其中文翻译通常是仓库,看起来词不达意,但是“repository system”通常被翻译为“处置库系统” ,瞬间了然。
所以spring data jpa的思想就可以被描述为spring data jpa是向某实体提供处置库(repository)的解决方案,至于这个处置库里到底包含了什么,我们下面继续说。
什么是Spring Data APIS?
再次强调,Spring Data JPA不是一个JPA供应商(例如hibernate)。它是一个在JPA供应商基础上增加的额外一个抽象层(处置库层),本质上是个库或者说框架。通常来说,如果我们选用Spring Data JPA,那么程序调用的方式就变成了如下的模式:
- Spring Data JPA:根据Spring Data的处置库接口,去创建一个JPA标准的处置库。
- Spring data common:Spring data project提供的数据存储基础框架。
- JPA供应商提供 Java Persitence API的实现。
下面这个图描述了处置库层的:
你一定在想,Spring data JPA的这种设计让我们的应用程序变得更加复杂了,哈哈,你猜对了。它确实在我们的处置层里追加了一层,但是,这种设计能让我们减少代码量。如果是这个目的的话,那么现在听起来,就还可以接受了吧?
Spring data Repositoris介绍
Spring data JPA层的本质是在程序处置层中根据Spring data common Project提供的接口做特定存储的子项目。 当然,我们在使用Spring data jpa的过程中,并不需要了解它是如何实现的抽象处置库,但是我们必须非常熟悉SPring data的处置接口。 这些接口主要包含下述内容:
第一层接口:SPring data Commons project提供如下的接口:
- Repository<T, ID extends Serializable> 接口:提供标记的接口,两个目的:
- 找到被管理实体的类型和其ID的类型
- 通过对classPath的扫描帮助Spring容器发现“具体”处置库接口。
- CrudRepository<T, ID extends Serializable> :对管理的实体提供增删改查操作
- PagingAndSortingRepository<T, ID extends Serializable> :当数据从数据库被还原到实体上之后,进行排序和分页。
- QueryDslPredicateExecutor<T>:非处置库接口,通过QueryDSL,将数据库查询的结果还原成实体。
第二层接口:Spring data JPA提供如下接口:
-
JpaRepository<T, ID extends Serializable> :JPA特定处置库,将JPA用到的通用处置库中的多个接口合并成一个。
-
JpaSpecificationExecutor<T> :非处置库接口,用于将数据库查询的结通过Specification<T>果还原成实体。
处置库的继承关系如下:
说的差不多了,但是我们怎么用它? 后面的文章会回答这个问题,但是原则上一般使用一下的步骤:
- 创建一个继承Spring data repository 的接口。
- 如果我们有特定需求,在这个接口中创建特定的执行方法。
- 将这个接口注入到其他系统组件中,我们就可以直接用了。
Repository(处置库)到底是什么?
个人理解,DAO(Data Access Object)层就是我们应用程序针对于数据库的Repository,它是程序中DO(Data Object)与数据库的桥梁,将程序对实体的操作,翻译成sql语言,这也是ORM的本质。
什么叫处置库?处置库里有什么?
更便于理解的叫法应该是“处理库”,这里放的是一些“处理方法”。对于数据库而言,我们的处理方法无非就是CRUD(create,Retrieve,Update,Delete),也就是我们说的增删改查。这也就是上文中“CrudRepository<T, ID extends Serializable>”产生的根本。
而实际业务中,我们对数据库的操作,可能更为细化,那么这些更加细化的需求,则是我们某个处置库里需要追加的特有的方法。
举例: 上文中的BaseDao就是通用处置库,而StudentDao则是一个学生对象特有的处置库。
QueryDSL参考
关于这部分内容,感兴趣可以参考QueryDSL的源码。
这里是项目的一个单元测试,可以感受一下效果。
assertEquals(Arrays.asList(),
query().from(entity, entity2)
.where(bigd1.add(bigd2).loe(new BigDecimal("1.00")))
.select(entity).fetch());
总结
本位尝试在描述下面的两件事:
- Spring data jpa 并不是一个JPA供应商,它是Java Persistence API (和JPA供应商)的在处置层(传统DAO层)的封装。
- Spring data为实现不同的目的,提供了多种接口。
下一章,我们将了解SPring data JPA的必要依赖。
备注
原文作者简介:
Petri Kainulainen is passionate about software development and continuous improvement. He is specialized in software development with the Spring Framework and is the author of Spring Data book.
声明:
这里并不是原文100%的翻译,而是追加了个人的一些想法和补充,原文地址在本文最上方,请自行判断阅读哪一个版本。