搭建SpringCloud微服务框架:六、数据库持久层-SpringDataJPA

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

搭建SpringCloud微服务框架:六、数据库持久层-SpringDataJPA

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

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

Github地址:SQuid


介绍

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

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

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


使用

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

搭建SpringCloud微服务框架:六、数据库持久层-SpringDataJPA

引入依赖:

<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可以了解一下

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 ages) …where x.age in ?1
NotInfindByAgeNotIn(Collection 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"),可以参考

贴上项目中的例子:

public interface EdocInvoiceService {

    List<EdocInvoice> findAll();

    EdocInvoice save(EdocInvoice edocInvoice);
}

@Service
public 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: true
server:
  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