对springboot的使用也是有一段时间了,在使用上确实简化了很多,也可以让一个刚入门的人迅速搭建一套开发环境来,但是随之而来的问题也比较显著,当框架本身无法满足需求或者需要在原有的基础上进行扩展,对原有的模块进行选择性的使用等等,都会带来巨大的麻烦,由于框架帮助我们预先定制了很多可能是比价不错的配置方式,但这些默认的,而这些约定的东西,我们理解多少,哪些复杂的构建关系又如何一眼看穿,所以效率提高了,但是灵活度也就依赖于更深层次的学习了。
同样,现在较为常用的ORM框架可能就是mybatis与hibernate了,做最简单的比较mybatis不管是在代码层面确实比hibernate少的不是一点点,然而功能上也显得没那么强大了,当然,这么说是它本身提供的功能,但是其本身侧重点却并非像hibernate那样,属于面向对象的ORM框架,可能其更多的是如何与数据库建立关联,而对数据库具体的操作,都留给开发者自己完成了,因此也就显得比较灵活。hibernate的繁重,更多的是其对单表操作的封装,开发者仅用其提供的api即可完成数据库CURD的所有操作。
今天说到JPA,其实只是一个java操作对数据进行持久化的一个标准,其提供了专有的API取操作数据库,那么实现了这个标准的框架,我们可以不用调用框架本身保留的API,通过JPA就能实现,因此JPA显得更向一个对提供数据持久的服务门面。hibernate属于实现了JPA规范的框架,而且比较流行,所以一般情况都是结合hibernate来调用JPA的api;
今天从以下几个方面来学习下,不会对springboot与jpa源码做讲解,仅仅是对其提供的功能进行深度开发:
-
jpa与springboot整合
由于springboot的特性,与其他框架整合显得比较容易,与因为springboot提供了很多自动配置模块,因此我们只需要引入相关的jar即可完成:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
现在比较习惯使用pring-boot-dependencies来构建项目,因为它帮助我们维护了大量相关jar的版本,不用在意混乱的版本导致系统问题。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.10.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
-
实现通用服务,构建企业开发环境
标准项目可能会有以下几个小模块组成,entity,dao,daoimpl,service,serviceimpl,web。
刚说到JPA作为一种规范,提供了以下标准的接口对外统一调用。我们常用的会有下面几个:
CrudRepository:实现基础的增删改查,主要根据主键操作
PagingAndSortingRepository:对上一个接口的加强,实现分页排序
JpaRepository:对上一个接口的加强,同时添加excmple查询
JpaSpecificationExecutor:通过Criteria动态查询
dao:继承jpa提供的机构,加上注解@Repository。可以通过定义自己的Repository来做加强,因为每种接口的功能不同,可以同时实现多个接口
service:可以定义公共接口,将常用的crud方法抽象出来
web:将一般的查询,比如根据id查询,根据条件查询,分页查询,新增/修改,删除等统一处理
扩展:
根据上面的接口关系,我们将dao继承JpaRepository则可以实现基础的增删改查,同时可以通过分页、排序、Example进行查询,要知道Example大部分是= ! > <相关的查询,
但是如果要实现多种类型的查询,比如< > in bwt...时,则无法满足需求,所有同时引入JpaSpecificationExecutor,通过Criteria进行更深层次的扩展。
-
表关系mappedBy、cascade的理解
mappedBy表示谁维护关系。
CascadeType:PERSIST主可以新增从;MERGE主可以修改从;REMOVE主可以删除从;REFRESH主不会影响从
-
事务处理
默认情况下,springboot会开启事务,在spring-boot-autoconfigure中,有几个关于Transaction的自动化配置
@EnableTransactionManagement,可以选择PROXY和ASPECT两种模式,具体什么区别,需要深入
-
测试
在通过entityManager,通过接口方法调用又全部正常进行测试时,一直提示没有事务(No transactional EntityManager available),但是系统正常运行时也没问题.
所以只能通过mock发送请求进行测试。
-
问题记录
一般户出现这样的错误:
1、Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException...
这是由于我们查询到的对象并非其本身,而是代理后的对象,在转换成json出了问题
在网上搜,一般给出的答案是在实体类上添加@JsonIgnoreProperties({ "handler","hibernateLazyInitializer","fieldHandler"})来忽略代理对象新加的属性,当然这样做看起来是解决了问题,
但是你会发现,你的所有fetch都会失效,那样效率就会出问题
正确的处理方式是添加
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>2.9.8</version>
</dependency>
在MappingJackson2HttpMessageConverter中添加一个objectMapper HibernateAwareObjectMapper.
这里仅仅做一个简单的讲解,没有怎么设计代码层面,主要也是由于代码方面比较复杂,闲时也会做一定的分析。
这里也针对上面说到的,做了一个具体的实现,主要完成了通用service与serviceImpl,通用web的实现,开发时只需要进行简单的继承即可完成单表的各种查询。当然同时扩展了各种条件查询、自定义sql查询等等。