Spring Data JPA 的使用

上一篇Spring JavaConfig中配置數據源使用了JPA,這裏就介紹一下Spring data jpa的經常使用方法.java

spring data jpa介紹

什麼是JPA

JPA(Java Persistence API)是Sun官方提出的Java持久化規範。它爲Java開發人員提供了一種對象/關聯映射工具來管理Java應用中的關係數據。spring

Spring Data JPA 是 Spring 基於 ORM 框架、JPA 規範的基礎上封裝的一套JPA應用框架,可以使開發者用極簡的代碼便可實現對數據的訪問和操做。它提供了包括增刪改查等在內的經常使用功能,且易於擴展!學習並使用 Spring Data JPA 能夠極大提升開發效率!app

spring data jpa讓咱們解脫了DAO層的操做,基本上全部CRUD均可以依賴於它來實現框架

簡單查詢dom

基本查詢也分爲兩種,一種是spring data默認已經實現,一種是根據查詢的方法來自動解析成SQL。工具

spring data jpa 默認預先生成了一些基本的CURD的方法,例如:增、刪、改等等學習

public interface ItemRepository extends JpaRepository<Item, Integer>, JpaSpecificationExecutor<Item> {
//空的,能夠什麼都不用寫
}複製代碼
@Test
public void test1() throws Exception {
    Item item = new Item();
    itemRepository.save(item);
    List<Item> itemList = itemRepository.findAll();
    Item one = itemRepository.findOne(1);
    itemRepository.delete(item);
    long count = itemRepository.count();
}複製代碼

自定義簡單查詢ui

Item findByItemName(String itemName);

List<Item> findByItemNameLike(String itemName);

Long deleteByItemId(Integer id);

List<Item> findByItemNameLikeOrderByItemNameDesc(String itemName);複製代碼

具體的關鍵字,使用方法和生產成SQL以下表所示spa

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 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 (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 ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection age) … 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)

分頁查詢code

Page<Item> findALL(Pageable pageable);複製代碼
@Test
public void test1() throws Exception {
    int page=1,size=10;
    Sort sort = new Sort(Sort.Direction.DESC, "id");//根據id降序排序
    Pageable pageable = new PageRequest(page, size, sort);
    Page<Item> pageResult = itemRepository.findALL(pageable);
    List<Item> itemList = pageResult.getContent();
}複製代碼

自定義SQL查詢

在SQL的查詢方法上面使用@Query註解,如涉及到刪除和修改在須要加上@Modifying.也能夠根據須要添加 @Transactional 對事物的支持

//自定分頁查詢 一條查詢數據,一條查詢數據量
@Query(value = "select i from Item i",
        countQuery = "select count(i.itemId) from Item i")
Page<Item> findall(Pageable pageable);

//nativeQuery = true 本地查詢 就是使用原生SQL查詢
@Query(value = "select * from item where item_id = ?1", nativeQuery = true)
Item findAllItemById(int id);

@Transactional
@Modifying
@Query("delete from Item i where i.itemId = :itemId")
void deleteInBulkByItemId(@Param(value = "itemId") Integer itemId);

//#{#entityName}就是指定的@Entity,這裏就是Item
 @Query("select i from #{#entityName} i where i.itemId = ?1")
 Item findById(Integer id);複製代碼

命名查詢

在實體類上使用@NameQueries註解

在本身實現的DAO的Repository接口裏面定義一個同名的方法

而後就可使用了,Spring會先找是否有同名的NamedQuery,若是有,那麼就不會按照接口定義的方法來解析。

//命名查詢
@NamedQueries({
        @NamedQuery(name = "Item.findItemByitemPrice",
                query = "select i from Item i where i.itemPrice between ?1 and ?2"),
        @NamedQuery(name = "Item.findItemByitemStock",
                query = "select i from Item i where i.itemStock between ?1 and ?2"),
})
@Entity
@Data
public class Item implements Serializable {
    @Id
    @GeneratedValue
    @Column(name = "item_id")
    private int itemId;
    private String itemName;
    private Integer itemPrice;
    private Integer itemStock;
 }複製代碼
/** * 這裏是在domain實體類裏@NamedQuery寫對應的HQL * @NamedQuery(name = "Item.findItemByitemPrice", baseQuery = "select i from Item i where i.itemPrice between ?1 and ?2"), * @param price1 * @param price2 * @return */
List<Item> findItemByitemPrice(Integer price1, Integer price2);
List<Item> findItemByitemStock(Integer stock1, Integer stock2);複製代碼

那麼spring data jpa是怎麼經過這些規範來進行組裝成查詢語句呢?

Spring Data JPA框架在進行方法名解析時,會先把方法名多餘的前綴截取掉,好比 find、findBy、read、readBy、get、getBy,而後對剩下部分進行解析。

假如建立以下的查詢:findByUserDepUuid(),框架在解析該方法時,首先剔除 findBy,而後對剩下的屬性進行解析
  1. 先判斷 userDepUuid (根據 POJO 規範,首字母變爲小寫)是否爲查詢實體的一個屬性,若是是,則表示根據該屬性進行查詢;若是沒有該屬性,繼續第二步;
  2. 從右往左截取第一個大寫字母開頭的字符串此處爲Uuid),而後檢查剩下的字符串是否爲查詢實體的一個屬性,若是是,則表示根據該屬性進行查詢;若是沒有該屬性,則重複第二步,繼續從右往左截取;最後假設user爲查詢實體的一個屬性;
  3. 接着處理剩下部分(DepUuid),先判斷 user 所對應的類型是否有depUuid屬性,若是有,則表示該方法最終是根據 Doc.user.depUuid 的取值進行查詢;不然繼續按照步驟 2 的規則從右往左截取,最終表示根據 Doc.user.dep.uuid 的值進行查詢。
  4. 可能會存在一種特殊狀況,好比 Doc包含一個 user 的屬性,也有一個 userDep 屬性,此時會存在混淆。能夠明確在屬性之間加上 "_" 以顯式表達意圖,好比 findByUser_DepUuid() 或者 findByUserDep_uuid()

原文連接:Spring Data JPA 的使用 | 火堯

相關文章
相關標籤/搜索