Spring boot解析: chapter5 JPA, SQL db

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Figure. 高層次抽象, 以JPA為例

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Figure. Repository interfaces: 藍色為spring data核心interface

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Specification 動態條件查詢


JPA提供Criteria查詢, Spring Data JPA則對Criteria進行封裝

  • api interface: SpecificationExecutor
    • long count(Specification<T> spec);
    • Optional<T> findOne(Specification<T> spec)
    • List<T> findAll(Specification<T> spec)
    • List<T> findAll(Specification<T> spec, Sort sort)
    • Page<T> findAll(Specification<T> spec, Pageable pageable)
  • Class specification 組合動態查詢條件
    • 定義一個方法需覆寫: Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
      • root 物件本身
      • query 最終語法
      • criteriaBuilder: 生成各種查詢語法(equal() ==, ge() >=, gt() >)
Specification<查詢目標類> specification = (root, query, criteriabuilder) -> {
	List<Predicate> predicates = new ArrayList<>();

	DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
	LocalDate start = LocalDate.parse(transReq.getStartDate(), formatter);
	LocalDate end = LocalDate.parse(transReq.getEndDate(), formatter);

	predicates.add(criteriabuilder.between(root.get("executeDate"), start, end));
    // select t from 目標類 where t.apid = ?1
	predicates.add(criteriabuilder.equal(root.get("apid"), apid));

	if (StringUtils.hasText(transReq.getiContactId())) {
		predicates.add(criteriabuilder.equal(root.get("eformId"), transReq.getiContactId()));
	}

	if (StringUtils.hasText(transReq.getChangeTypeId())) {
		predicates.add(criteriabuilder.equal(root.get("changeTypeId"), transReq.getChangeTypeId()));
	}

	if (StringUtils.hasText(transReq.getIsActive())) {
		predicates.add(criteriabuilder.equal(root.get("isActive"), transReq.getIsActive()));
	}
    // where: 根據特定的predicate產生特定的specification, 參數為陣列
    // 轉成陣列: predicates.toArray(new Predicate[predicates.size()])
    // 最後透過getRestriction()取得對應的predicate
	return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
};

Repository 需繼承JpaSpecificationExecutor

public interface SreEformChangeinfoRepository
		extends JpaRepository<SreEformChangeinfo, String>, JpaSpecificationExecutor<SreEformChangeinfo> {

// 通常會再寫靜態方法來組合查詢條件, 如前面的Specification的部分
}

Parameter binding

預設以位置(position-based) binding,這種方法容易導致錯誤,@Query做name binding的方式
(1) @Param註解,例如:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

(2) 在Java 8以上的版本,javac compile flag 能傳入 -parameter,gradle可傳入參數
TODO: 傳入flag,但測試API仍未解決
Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

(3) Eclipse對應的設定方法:store information about method parameters
Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

-parameters @Param的差別

  1. -parameters Compiler Option
    編譯Java source code時使用,若Java class包含方法參數,由於效能考量及減少編譯程式的size,參數名稱通常不會從編譯好的bytecode取得,這個參數告訴compiler要包含parameter names在compiled bytecode,包含參數名稱有利於依賴反射的tools及frameworks,像是在web frameworks HTTP request binding的parameters
    javac -parameters MyClass.java
  2. @param Javadoc Tag (Spring data JPA)
    用來標記Java方法及constructor的參數,map方法參數到自定義sql query的placeholder(外部取用),不涉略編譯過程,而 @param 主要是用於生成文檔,提供對方法參數的說明,顯示指定名稱。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
兩者的用途不同,使用-parameters可omit @Param,但就要另加注意命名與sql query的變數名稱一致

@Repository
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {

    @Query("SELECT e FROM MyEntity e WHERE e.someProperty = :paramValue")
    List<MyEntity> findBySomeProperty(@Param("paramValue") String testValue);
}

參考