SpringBoot整合系列-整合JPA

原創做品,能夠轉載,可是請標註出處地址:https://www.cnblogs.com/V1haoge/p/9959865.htmlhtml

SpringBoot整合JPA進行數據庫開發

步驟

第一步:添加必要的jar包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>com.querydsl</groupId>
  <artifactId>querydsl-apt</artifactId>
  <version>${querydsl.version}</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>com.querydsl</groupId>
  <artifactId>querydsl-jpa</artifactId>
  <version>${querydsl.version}</version>
</dependency>

第二步:添加必要的配置

spring.datasource.url = jdbc\:h2\:file\:D\:\\testdb;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username = sa
spring.datasource.password = sa
spring.datasource.driverClassName =org.h2.Driver

第三步:添加實體,並添加註解

@Entity  
@Table(name = "USER")
public class User {  
     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     private int useId;
     @Column 
     private String useName; 
     @Column 
     private UseSex useSex; 
     @Column 
     private int useAge; 
     @Column(unique = true)
     private String useIdNo; 
     @Column(unique = true)
     private String usePhoneNum; 
     @Column(unique = true)
     private String useEmail; 
     @Column 
     private LocalDateTime createTime; 
     @Column 
     private LocalDateTime modifyTime;
     @Column 
     private UseState useState;
 }

第四步:添加持久層

@Repository  
public interface UserRepository extends JpaRepository {  
}

注意: 繼承自JpaRepository的持久層能夠直接使用其定義好的CRUD操做,其實只有增刪查操做,關於修改的操做仍是須要自定義的。java

第五步:持久層的使用

@Service  
public class UserService {  
     @Autowired 
     private UserRepository repository; 
     public ResponseEntity addUser(final User user) { 
         return new ResponseEntity<>(repository.save(user),HttpStatus.OK); 
     }
}

注意:其實在JpaRepository中已經定義了許多方法用於執行實體的增刪查操做。spring

JPA高級功能

方法名匹配

在UserRepository中定義按照規則命名的方法,JPA能夠將其自動轉換爲SQL,而免去手動編寫的煩惱,好比定義以下方法:sql

User getUserByUseIdNo(String useIdNo);

JPA會自動將其轉換爲以下的SQL:數據庫

select * from USER where use_id_no = ?

下面簡單羅列方法命名規則:ide

關鍵字 例子 sql
And findByNameAndAge ...where x.name=?1 and x.age=?2
Or findByNameOrAge ...where x.name=?1 or x.age=?2
Between findByCreateTimeBetween ...where x.create_time between ?1 and ?2
LessThan findByAgeLessThan ...where x.age < ?1
GreaterThan findByAgeGreaterThan ...where x.age > ?1
IsNull findByAgeIsNull ...where x.age is null
IsNotNull,NotNull findByAgeIsNotNull ...where x.age not null
Like findByNameLike ...where x.name like ?1
NotLike findByNameNotLike ...where x.name not like ?1
OrderBy findByAgeOrderByNameDesc ...where x.age =?1 order by x.name desc
Not findByNameNot ...where x.name <>?1
In findByAgeIn ...where x.age in ?1
NotIn findByAgeNotIn ...where x.age not in ?1

@Query註解

    使用@Query註解在接口方法之上自定義執行SQL。spring-boot

@Modifying
@Query(value = "update USER set USE_PHONE_NUM = :num WHERE USE_ID= :useId", nativeQuery = true)
void updateUsePhoneNum(@Param(value = "num") String num, @Param(value = "useId") int useId);

    上面的更新語句必須加上@Modifying註解,其實在JpaRepository中並未定義更新的方法,全部的更新操做均須要咱們本身來定義,通常採用上面的方式來完成。this

/**
 * 表示一個查詢方法是修改查詢,這會改變執行的方式。只在@Query註解標註的方法或者派生的方法上添加這個註解,而不能
 * 用於默認實現的方法,由於這個註解會修改執行方式,而默認的方法已經綁定了底層的APi。
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Documented
public @interface Modifying {
	boolean flushAutomatically() default false;
	boolean clearAutomatically() default false;
}

JPQL(SQL拼接)

    使用JPQL須要在持久層接口的實現列中完成,即UserRepositoryImpl,這個類是UserRepository的實現類,咱們在其中定義JPQL來完成複雜的SQL查詢,包括動態查詢,連表查詢等高級功能。url

QBE(QueryByExampleExecutor)

    使用QBE來進行持久層開發,須要用到兩個接口類,Example和ExampleMatcher,開發方式以下:spa

List users = repository.findAll(Example.of(user));

    或者配合ExampleMarcher使用:

ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreCase();
List users = repository.findAll(Example.of(user, matcher));

    以上邏輯通常位於service之中。其中user模型中保存着查詢的條件值,null的字段不是條件,只有設置了值的字段纔是條件。ExampleMatcher是用來自定義字段匹配模式的。

處理枚舉

​ 使用Spring-Data-Jpa時,針對枚舉的處理有兩種方式,對應於EnumType枚舉的兩個值:

public enum EnumType {
    /** Persist enumerated type property or field as an integer. */
    ORDINAL,
    /** Persist enumerated type property or field as a string. */
    STRING
}

​ 其中ORDINAL表示的是默認的狀況,這種狀況下將會將枚舉值在當前枚舉定義的序號保存到數據庫,這個須要是從0開始計算的,正對應枚舉值定義的順序。STRING表示將枚舉的名稱保存到數據庫中。

​ 前者用於保存序號,這對枚舉的變動要求較多,咱們不能隨便刪除枚舉值,不能隨意更改枚舉值的位置,並且必須以0開頭,而這通常又與咱們定義的業務序號不一致,限制較多,一旦發生改變,很可能形成業務混亂;後者較爲穩妥。

​ 正常狀況下,若是不在枚舉字段上添加@Enumerated註解的話,默認就以ORDINAL模式存儲,若要以STRING模式存儲,請在枚舉字段上添加以下註解:

@Enumerated(EnumType.STRING)
@Column(nullable=false) // 通常要加上非null約束
private UseState useState;

分頁功能

​ Spring-Data-Jpa中實現分頁使用到了Pageable接口,這個接口將做爲一個參數參與查詢。

​ Pageable有一個抽象實現類AbstractPageRequest,是Pageable的抽象實現,而這個抽象類有兩個實現子類:PageRequest和QPageRequest,前者現已棄用,如今咱們使用QPageRequest來定義分頁參數,其有三個構造器:

public QPageRequest(int page, int size) {
    this(page, size, QSort.unsorted());
}
public QPageRequest(int page, int size, OrderSpecifier<?>... orderSpecifiers) {
    this(page, size, new QSort(orderSpecifiers));
}
public QPageRequest(int page, int size, QSort sort) {
    super(page, size);
    this.sort = sort;
}

​ 在這裏面咱們能夠看到一個QSort,這個QSort是專門用於與QPageRequest相配合使用的類,用於定義排序規則。默認狀況下采用的是無排序的模式,即上面第一個構造器中的描述。

​ 要構造一個QSort須要藉助querydsl來完成,其中須要OrderSpecifier來完成。

​ 這裏有個簡單的用老版本實現的分頁查詢:

public ResponseEntity<Page<User>> getUserPage(final int pageId) {
        Sort sort = new Sort(new Sort.Order(Sort.Direction.DESC, "useId"));
        Page<User> users = repository.findAll(new PageRequest(pageId,2, sort));
        return new ResponseEntity<>(users, HttpStatus.OK);
    }

​ 至於新版本的分頁查詢和排序涉及內容較多較複雜,稍後再看。

注意:分頁首頁頁碼爲0

相關文章
相關標籤/搜索