搭建微服务框架(数据库持久层-SpringDataJPA)

用惯了Mybatis,这次来换换口味,在SQuid中集成SpringDataJPA。

本文源地址:搭建微服务框架(数据库持久层-SpringDataJPA)

Github地址:SQuid


介绍

以前都是听说过的是 HibernateJPA ,却从来没有使用过,一直在项目中使用的是 Mybatis

SpringDataJPA是基于Hibernate的底层封装的一套ORM框架,使用起来的第一感觉是代码量真的很少,相较传统的Mybatis来说,感觉最起码少了60%,当然大部分都是体现在xml文件上。

介绍真的没有太多词汇可以展示出来,下面来进行使用。?


使用

在squid项目中,我们新建一个 squid-example-jpa的项目(由于之前的example目录被删除,可以根据下面的层级目录来进行新建)

引入依赖:
<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency>    <groupId>com.alibaba</groupId>    <artifactId>druid-spring-boot-starter</artifactId></dependency><dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId></dependency><dependency>    <groupId>org.projectlombok</groupId>    <artifactId>lombok</artifactId>    <optional>true</optional></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-test</artifactId></dependency>
生成Java实体

如果使用的是IDEA,完全可以参考这篇博客 IDEA下生成SpringDataJPA的Java实体
来生成实体信息。

因为使用了lombok,所以在生成的实体中并没有 getter setter 方法呈现,关于lombok可以了解一下 Lombok

DAO

生成了实体信息后,DAO文件就需要我们自己来手工生成了:

public interface EdocInvoiceRepository extends JpaRepository<EdocInvoice, Long> {}

一般我们直接继承的是 JpaRepository ,这个是包含所有JPA处理的类,基本上拥有了所有持久层的交互方法。

JPARespository:

public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {    List<T> findAll();    List<T> findAll(Sort var1);    List<T> findAllById(Iterable<ID> var1);    <S extends T> List<S> saveAll(Iterable<S> var1);    void flush();    <S extends T> S saveAndFlush(S var1);    void deleteInBatch(Iterable<T> var1);    void deleteAllInBatch();    T getOne(ID var1);    <S extends T> List<S> findAll(Example<S> var1);    <S extends T> List<S> findAll(Example<S> var1, Sort var2);}

如果你还有其他需求,比如需要根据某两个字段进行查询等等,SpringDataJPA完全支持:

KeywordSamplePQL snippet
AndfindByLastnameAndFirstnamewhere x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstnamewhere x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals …where x.firstname = ?1
BetweenfindByStartDateBetween …where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan …where x.age < ?1
LessThanEqualfindByAgeLessThanEqual …where x.age <= ?1
GreaterThanfindByAgeGreaterThan …where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual …where x.age >= ?1
AfterfindByStartDateAfter …where x.startDate > ?1
BeforefindByStartDateBefore …where x.startDate < ?1
IsNullfindByAgeIsNull …where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull …where x.age not null
LikefindByFirstnameLike …where x.firstname like ?1
NotLikefindByFirstnameNotLike ... findByFirstnameNotLike
StartingWithfindByFirstnameStartingWith …where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith …where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining …where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc …where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot …where x.lastname <> ?1
InfindByAgeIn(Collection<Age> ages) …where x.age in ?1
NotInfindByAgeNotIn(Collection<Age> ages) …where x.age not in ?1
TruefindByActiveTrue() …where x.active = true
FalsefindByActiveFalse() …where x.active = false
IgnoreCasefindByFirstnameIgnoreCase …where UPPER(x.firstame) = UPPER(?1)

也可以访问SpringDataJPA的官方文档查看:SpringDataJPA

Service & Impl & Controller

service、service.impl,controller,按照常规项目中来编写就行,其中需要注意的是,service如果是要作为对外接口,可以注明 @FeignClient("squid-example-jpa"),可以参考 sc-server

贴上项目中的例子:

public interface EdocInvoiceService {    List<EdocInvoice> findAll();    EdocInvoice save(EdocInvoice edocInvoice);}@Servicepublic class EdocInvoiceServiceImpl implements EdocInvoiceService {    @Autowired    private EdocInvoiceRepository edocInvoiceRepository;    @Override    public List<EdocInvoice> findAll() {        return edocInvoiceRepository.findAll();    }    @Override    public EdocInvoice save(EdocInvoice edocInvoice) {        return edocInvoiceRepository.save(edocInvoice);    }}@RestController@RequestMapping(value = "/invoice")public class EdocInvoiceController {    @Autowired    private EdocInvoiceService edocInvoiceService;    @PostMapping(value = "/findAll")    public List<EdocInvoice> findAll() {        return edocInvoiceService.findAll();    }    @PostMapping(value = "/save")    public EdocInvoice save(@RequestBody EdocInvoice edocInvoice) {        return edocInvoiceService.save(edocInvoice);    }}
application.yaml
spring:  application:    name: squid-miniprogram  datasource:    driver-class-name: com.mysql.jdbc.Driver    url: jdbc:mysql://yanzhenyidai.com:3306/fapiaochi?useUnicode=true&characterEncoding=utf-8    username: root    password: ***    type: com.alibaba.druid.pool.DruidDataSource  jpa:    hibernate:      ddl-auto: update    show-sql: trueserver:  port: 9090

jpa.hibernate.ddl-auto

keyvalue
create启动时删数据库中的表,然后创建,退出时不删除数据表
create-drop启动时删数据库中的表,然后创建,退出时删除数据表 如果表不存在报错
update如果启动时表格式不一致则更新表,原有数据保留
validate项目启动表结构进行校验 如果不一致则报错

一般的 ddl-auto 属性使用 update 就行。

多表查询

复杂业务出现时,可能会使用到多表查询,但是JPA不像Mybatis那么灵活,需要创建中间实体来进行接收,我一般的做法两张表分开查询,然后合并。


## 总结

SpringDataJPA使用起来的感受就是一个字 “” ,相较于比较小型的项目,真的推荐使用SpringDataJPA,它能快速的搭建起一个持久层,也不用像Mybatis一样太多的关心底层的xml文件。

参考资料:

SpringDataJPA-Github

SpringDataJPA-doc