spring data jpa从入门到精通_Spring Data JPA 入门,有这一篇就够了!

a20ce9fc0906aee0babb221e07363383.png

最近对 Spring Data JPA 进行了一些研究,基本上是参考 Spring Data JPA - Reference Documentation 官方文档,总结分享出来,大家可以了解一下 Spring Data JPA 的基本用法。

01Introduction

官方定义:

Spring Data JPA, part of the larger Spring Data family, makes it easy to easily implement JPA based repositories. This module deals with enhanced support for JPA based data access layers. It makes it easier to build Spring-powered applications that use data access technologies.

要解释清楚 Spring Data JPA 是什么,那么需要一步步说起:

  • 期初 JAVA 需要通过各个数据库厂商提供的API进行数据库的访问,后来 JAVA 提出了 JDBC,程序直接使用 JDBC 这套规范就可以跟各个数据库进行对接;

  • 接着诞生了 ORM 技术,简化了 Java 对象的持久化工作,出现了 Hibernate、 TopLink 等 ORM 框架;

  • Sun 公司在 JDK1.5 的时候,吸收了 Hibernate、 TopLink等 ORM 框架的优点,提出了 Java 持久化规范:JPA ;

  • Hibernate 在 3.2 的时候提供了 JPA 的实现,其余的 JPA 的供应商还有诸如 OpenJPA、 Toplink等;Spring 在做持久化这一块的工作,开发了 Spring-data-xxx 这一系列包,如:Spring-data-jpa, Spring-data-redis, Spring-data-mongodb 等等,这些都是 Spring 提供的基于 JPA 和其他一些 NOSQL 的 Repository。

Spring Data JPA 是在 JPA 规范的基础下提供了 Repository 层的实现,但是使用哪一款 ORM 需要你自己去决定;相比我们更为熟悉的 Hibernate 和 MyBatis, Spring Data JPA 可以看做更高层次的抽象。

02 Dependencies

具体步骤可以参考官网:[spring-data-jpa/quick-start]

        <dependency>            <groupId>org.springframework.datagroupId>            <artifactId>spring-data-jpaartifactId>        dependency></dependencies>

如果要在Spring Boot下使用Spring Data JPA的话,需要引入:

<dependency>      <groupId>org.springframework.bootgroupId>      <artifactId>spring-boot-starter-data-jpaartifactId>dependency>
03 Working with Spring Data Repositories

让我们看一个简单的例子,实现增删查改的功能;从例子中我们可以发现,可以通过方法名称的定义,就可以达到 SQL 的效果:

比如 findByName(String name) 就相当于:

select * from user where name = ?
public interface UserCrudRepository                   extends CrudRepository<User, String>{        User findOne(String userid);        List findByName(String name);        List findByNameAndAgeLessThan(String name, int age);        void deleteByNameAndAgeLessThan(String name, int age);        List findDistinctByName(String name);        List findByNameIgnoreCase(String name);        User findFirstByOrderByUseridDesc();}
04 Repositories

Spring Date JPA提供了几个接口:

  • Repository:最顶层的接口,是一个空的接口,目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别。
  • CrudRepository:是Repository的子接口,提供CRUD的功能。
  • PagingAndSortingRepository :是CrudRepository的子接口,添加分页和排序的功能。
  • JpaRepository :是PagingAndSortingRepository的子接口,增加了批量操作等功能。

以上四个 XxxRepositoty 越来越具体、功能越来越丰富,从使用的角度应该是继承自己用到的最小集,如需扩展再做调整,嫌麻烦的话直接继承 JpaRepository 也没关系。

05 Query creation

可以直接使用 CrudRepository 中的 findOne 和 findAll 方法:

public interface UserCrudRepository                   extends CrudRepository{    /**     * CrudRepository 中存在的方法,这里可以不写此方法      * CrudRepository中存在的方法:     * https://github.com/spring-projects/spring-data-commons/blob/master/src/main/java/org/springframework/data/repository/CrudRepository.java#L27     */    User findOne(String userid);    /**     * 查询所有 可以不写此方法      * 不写,需要在查询完成后强转:List userAfterDel = (List) this.repository.findAll();     * 写:List userAfterDel = this.repository.findAll();     */    //List findAll();}

也可以对查询方法进行扩展,扩展的格式为:find…By, read…By, query…By, get…By, count…By 。

public interface UserCrudRepository                    extends CrudRepository<User, String>{    /**     * 按照姓名查询,非主键 更多用法参考:     * http://docs.spring.io/spring-data/jpa/docs/1.10.6.RELEASE/reference/html/#new-features.1-10-0     * Table 4. Supported keywords inside method names     *     * @param name     * @return     */    ListfindByName(String name);     ListqueryByName(String name);     ListfindByNameAndAgeLessThan(String name, int age);     ListfindDistinctByName(String name);       ListfindByNameIgnoreCase(String name);}

如果数据库字段带有[ _ ]符号的,JAVA的Entity类中对应的属性不能带有[ _ ],需要通过@Column(name = "")标签进行关联。

如果JAVA的Entity类中属性按照驼峰格式命名,也需要通过@Column(name = "")标签进行关联。

06 Naming Strategy

解决上面的第二点问题:如果 JAVA 的 Entity 类中属性按照驼峰格式命名,也需要通过 @Column(name = "") 标签进行关联。

JPA 中的 NamingStrategy 接口(最先是 Hibernate 中提出),实现接口中的表名与列名命名函数,可以完成自己的命名策略设定。

举个例子,我们经常会遇到这样的问题,表的列明都是带的:user_id,user_name…,如果 User.java 中的属性都是不带  的,那么需要使用 @Column 标签进行和数据库字段的绑定:

@Entity@Table(name = "USER")@Datapublic class User {  @Column(name = "user_id")  @Id  private String userId;   @Column(name = "user_name")  //如果这样的字段很多,也是一个比较大的工作量  private String userName;}

而通过 NamingStrateg y接口的实现,可以统一的完成驼峰转下划线的功能,userId → user_id 、 userName → user_name;

Spring Boot提供了Configure JPA properties,我们可以可以直接在application.yml中进行配置:

spring.jpa.hibernate.naming.physical-strategy = com.example.MyPhysicalNamingStrategy

解决上面的第二点问题:如果 JAVA 的 Entity 类中属性按照驼峰格式命名,也需要通过 @Column(name = "") 标签进行关联。

在Hibernate5中,提供了两种映射策略:

--不做任何修改,userId→ userId,userid → useridspring.jpa.hibernate.naming.physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl        --将驼峰修改成下划线,userId → user_id,如果不做配置,默认这个策略spring.jpa.hibernate.naming.physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy  
@Entity@Table(name = "USER")@Datapublic class User {  @Id  private String userId;  //不需要在使用@Column(name = "user_id"),会自动转成 user_id   private String userName; //自动转成 user_name}

同时会有一个问题,如果数据库中表的列名规则不统一,比如有些带下划线,有些不带下划线的话,那么在编写Entity的时候,带下划线的字段写成驼峰格式,不带下划线的字段写成全小写,看起来也比较怪异。

@Entity@Table(name = "USER")@Datapublic class User {  @Id  private String userId;  //不需要在使用@Column(name = "user_id")   private String userName;   private String cardid;  //列名为 cardid ,不带下划线,所以这里不能写成驼峰格式,但是从代码风格上看,感觉比较怪异}

如果有更特殊的要求,例如数据库中所有的表或者字段都带固定格式的前缀,CSC_USER 表,字段有CSC_USER_ID, CSC_USER_NAME,可以自己去实现 NamingStrategy 接口(如果是 Spring Boot 的话,需要实现 PhysicalNamingStrategy 接口),在里面去增加前缀名称。

07 Naming Strategy

使用 @Query Annotation 绑定SQL语句(这样写,看起来是不是更直观):

public interface UserCrudRepository                   extends CrudRepository<User, String>{    //@Query("select u from User u where u.name = ?1")    //@Query("select u from User u where 1=1 and u.name = ?1")    //@Query("select u.userid from User u where 1=1 and u.name = ?1")    //@Query(value="select * from User u where u.name = ?1", nativeQuery = true)    ListfindByName(String name);}

使用 @Param Annotation 可以将参数中的名字和query中的名字进行绑定:

public interface UserCrudRepository                    extends CrudRepository{    @Query("select u from User u where u.name = :name and u.gender = :gender")    List findUsersByNameAndGender(@Param("name")String name , @Param("gender")String gender);}
08 Using Sort
public interface UserCrudRepository                    extends CrudRepository<User, String>    //可以使用 UserCrudRepository    //在方法使用 OrderBy    List<User> findByOrderByUseridDesc();}
public interface UserPageRepository                   extends PagingAndSortingRepository<User, String> {      //使用 Sort     ListfindAll(Sort sort);}
09 Using Pageable

需要继承PagingAndSortingRepository 或更高级的 JpaRepository 。

public class UserPageRepositoryTest {  @Test  public void findPageable() throws Exception {    Page usersPageOne = this.repository.findAll(new PageRequest(0, 2)); //1.PageRequest(int page, int size) 2.page从0开始         assertThat(usersPageOne.getContent().size()).isEqualTo(2);    assertThat(usersPageOne.getContent().get(0).getUserId()).isEqualTo("1");    assertThat(usersPageOne.hasPrevious()).isEqualTo(false);  //判断是否有上一页         Page usersPageTwo = this.repository.findAll(usersPageOne.nextPageable());  //查询下一页    assertThat(usersPageTwo.getContent().size()).isEqualTo(2);    assertThat(usersPageTwo.getContent().get(0).getUserId()).isEqualTo("3");  }}

也可以通过 [first] 或 [top] 关键字,取得结果集的前N条数据。

public interface UserCrudRepository                    extends CrudRepository<User, String>{    User findFirstByOrderByUseridDesc();    User findFirstByGenderOrderByUseridDesc(String gender);}
10 Save and Delete methods

保存一个 Entity 需要使用 CrudRepository.save(…) 方法,包括 Insert 和 Update。

Delete 方法基本可以参考 Query 方法,除了 delete() 和 deleteAll() 之外,还可以使用 deleteBy… 的方式,同样也可以使用 @query 标签。

在 JpaRepository 接口中,提供了 deleteInBatch() 的方法:

Deletes the given entities in a batch which means it will create a single {@link Query}.
11 Why use Spring Date JPA

可以看出 Spring Data JPA 和常用的 Hibernate 和 MyBatis 相比,在编码上更简洁,减少 Boilerplate Code。

实际上交易型的微服务应用的查询通常只是明细查询或简单的列表查询,而真正的复杂查询或者数据分析通常应是另建应用或者全文检索或者 ODS/DW 之类、并从交易型微服务同步数据,而这一部分是走 MyBatis 还是 NOSQL 另说。

Feign 虽然解决的不是 Spring Data Repository 同一个领域的问题,但是实现哲学是一致的,通过接口、COC 尽量减少 Rest 调用的 Boilerplate Code。

@FeignClient(url = "https://api.github.com")interface GitHubClient {      @RequestMapping(method = RequestMethod.GET, value = "/repos/{owner}/{repo}/contributors")    List contributors(@RequestParam("owner") String owner, @RequestParam("repo") String repo); }
640

f23554f2d03df126a4e5b7b06f5d13fc.png

ec56a2a1a97511628c205a116e52e001.png点再看的工资都翻了倍 fa8608e188f84241cdd2ccbfb272d829.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值