乐趣区

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

搭建微服务框架(数据库持久层 -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 完全支持:

Keyword Sample PQL snippet
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 … findByFirstnameNotLike
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<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … 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);
}

@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

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

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

多表查询

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


## 总结

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

参考资料:

SpringDataJPA-Github

SpringDataJPA-doc

退出移动版