SpringBoot全家桶Spring Boot

SpringBoot 全家桶 | JPA实例详解

2020-08-28  本文已影响0人  码农StayUp

本文源码:Gitee·点这里

参考

Spring Data JPA

引入包

引入jpa的包,同时引入mysql包和test

<dependencys>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
</dependencys>

配置文件

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot-familay?charset=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root
    hikari:
      maximum-pool-size: 32
      minimum-idle: 8
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update

实体类

代码省略了get/set方法

@Entity
@Table(name = "AUTH_USER")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 32)
    private String name;

    @Column(length = 32, unique = true)
    private String account;

    @Column(length = 63)
    private String pwd;

    @Column
    private Date createTime;
}

以上创建好后,程序启动后会自动在数据库中创建表信息

持久层

定义持久层接口

JPA中实现持久层非常简单,创建一个接口,并继承 org.springframework.data.jpa.repository.JpaRepository<T, ID>T为实体类,ID为实体类主键类型;最后在接口上增加 @Repository 注解

@Repository
public interface UserDao extends JpaRepository<User, Long> {
}

JpaRepository继承了CrudRepository,提供了基本的CRUD功能

public interface CrudRepository<T, ID extends Serializable>
  extends Repository<T, ID> {

  <S extends T> S save(S entity);      //(1)

  Optional<T> findById(ID primaryKey); //(2)

  Iterable<T> findAll();               //(3)

  long count();                        //(4)

  void delete(T entity);               //(5)

  boolean existsById(ID primaryKey);   //(6)

  // … more functionality omitted.
}

JpaRepository继承了PagingAndSortingRepository,提供分页和排序功能

public interface PagingAndSortingRepository<T, ID extends Serializable>
  extends CrudRepository<T, ID> {

  Iterable<T> findAll(Sort sort);

  Page<T> findAll(Pageable pageable);
}

定义查询方法

JPA可以通过方法名称派生查询

官方示例:

interface PersonRepository extends Repository<User, Long> {

  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // Enables the distinct flag for the query
  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

  // Enabling ignoring case for an individual property
  List<Person> findByLastnameIgnoreCase(String lastname);
  // Enabling ignoring case for all suitable properties
  List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

  // Enabling static ORDER BY for a query
  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}

方法名称中支持的关键字

Keyword Sample JPQL 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 … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1(参数附加了%)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1(参数与前缀%绑定)
Containing findByFirstnameContaining … where x.firstname like ?1(参数绑定在%中)
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)

查询返回类型

Return type Description
void 表示没有返回值。
Primitives Java primitives.
Wrapper types Java 包装器类型。
T 唯一实体。期望查询方法最多返回一个结果。如果未找到结果,则返回null。一个以上的结果触发IncorrectResultSizeDataAccessException
Iterator<T> 一个Iterator
Collection<T> A Collection
List<T> A List
Optional<T> Java 8 或 Guava Optional。期望查询方法最多返回一个结果。如果未找到结果,则返回Optional.empty()Optional.absent()。多个结果触发IncorrectResultSizeDataAccessException
Option<T> Scala 或 Javaslang Option类型。语义上与前面描述的 Java 8 的Optional相同。
Stream<T> Java 8 Stream
Future<T> A Future。期望使用@AsyncComments 方法,并且需要启用 Spring 的异步方法执行功能。
CompletableFuture<T> Java 8 CompletableFuture。期望使用@AsyncComments 方法,并且需要启用 Spring 的异步方法执行功能。
ListenableFuture A org.springframework.util.concurrent.ListenableFuture。期望使用@AsyncComments 方法,并且需要启用 Spring 的异步方法执行功能。
Slice 一定大小的数据块,用于指示是否有更多可用数据。需要Pageable方法参数。
Page<T> Slice以及其他信息,例如结果总数。需要Pageable方法参数。
GeoResult<T> 具有附加信息(例如到参考位置的距离)的结果条目。
GeoResults<T> GeoResult<T>列表以及其他信息,例如到参考位置的平均距离。
GeoPage<T> PageGeoResult<T>,例如到参考位置的平均距离。
Mono<T> 使用 Reactive 存储库的 Project Reactor Mono发出零或一个元素。期望查询方法最多返回一个结果。如果未找到结果,则返回Mono.empty()。多个结果触发IncorrectResultSizeDataAccessException
Flux<T> Project Reactor Flux使用 Reactive 存储库发出零,一个或多个元素。返回Flux的查询也可以发出无限数量的元素。
Single<T> 使用 Reactive 存储库发出单个元素的 RxJava Single。期望查询方法最多返回一个结果。如果未找到结果,则返回Mono.empty()。多个结果触发IncorrectResultSizeDataAccessException
Maybe<T> 使用 Reactive 存储库的 RxJava Maybe发出零或一个元素。期望查询方法最多返回一个结果。如果未找到结果,则返回Mono.empty()。多个结果触发IncorrectResultSizeDataAccessException
Flowable<T> RxJava Flowable使用 Reactive 存储库发出零个,一个或多个元素。返回Flowable的查询也可以发出无限数量的元素。

异步查询结果

我们在这里重点讲一下异步查询结果。
JPA查询结果支持异步,这意味着该方法在调用时立即返回,而实际查询的执行已提交给Spring的TaskExecutor的任务中。
官方示例:

interface PersonRepository extends Repository<User, Long> {
    @Async
    Future<User> findByFirstname(String firstname);               //(1)
    
    @Async
    CompletableFuture<User> findOneByFirstname(String firstname); //(2)
    
    @Async
    ListenableFuture<User> findOneByLastname(String lastname);    //(3)
}

使用SQL语句查询

JPA自定义查询语句非常简单,使用@Query注解即可

public interface UserDao extends JpaRepository<User, Long> {

    @Query("select u from User u where u.account = ?1")
    User selectByAccount(String account);

    @Transactional
    @Modifying
    @Query("update User u set u.pwd = ?2 where u.id = ?1")
    int updatePassword(Long id, String password);

}

实体关系映射

JPA 实体关系映射:@OneToOne 一对一关系、@OneToMany @ManyToOne 一对多和多对一关系、@ManyToMany 多对多关系。

OneToOne

一对一关系,即两个表中的数据是一一对应关系,这种主要应用到对象的扩展信息中。

用户实体类:

@Entity
@Table(name = "AUTH_USER")
public class User {

    /*
        其余代码省略
     */

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "user")
    private UserDetail userDetail;
}

用户详情实体类:

@Entity
@Table(name = "AUTH_USER_DETAIL")
public class UserDetail {

    /*
        其余代码省略
     */

    @OneToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
    private User user;
}

OneToMany/ManyToOne

一对多关系即一个表中的一行数据关联另外一个表中的多行数据,多对一与之相反。

用户实体类:

@Entity
@Table(name = "AUTH_USER")
public class User {

    /*
        其余代码省略
     */

    @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
    private Company company;
}

公司实体类:

@Entity
@Table(name = "AUTH_COMPANY")
public class Company {

    /*
        其余代码省略
     */

    @OneToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY, mappedBy = "company")
    private Set<User> users = new HashSet<>();
}

ManyToMany

多对多关系即其中一个表中的一行,与另一表中的多行关联,比如本示例中用户和角色的关系。

用户实体类:

@Entity
@Table(name = "AUTH_USER")
public class User {

    /*
        其余代码省略
     */

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<Role> roles = new HashSet<>();
}

角色实体类:

@Entity
@Table(name = "AUTH_ROLE")
public class Role {

    /*
        其余代码省略
     */

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "roles")
    private Set<User> users = new HashSet<>();
}

完整代码

springboot-jpa

timg (1).jpg
上一篇 下一篇

猜你喜欢

热点阅读