上一篇Spring JavaConfig中配置數(shù)據(jù)源使用了JPA,這里就介紹一下Spring data jpa的常用方法.
spring data jpa介紹
什么是JPA
JPA(Java Persistence API)是Sun官方提出的Java持久化規(guī)范。它為Java開發(fā)人員提供了一種對象/關(guān)聯(lián)映射工具來管理Java應(yīng)用中的關(guān)系數(shù)據(jù)。
Spring Data JPA 是 Spring 基于 ORM 框架、JPA 規(guī)范的基礎(chǔ)上封裝的一套JPA應(yīng)用框架油坝,可使開發(fā)者用極簡的代碼即可實現(xiàn)對數(shù)據(jù)的訪問和操作涂籽。它提供了包括增刪改查等在內(nèi)的常用功能考传,且易于擴展!學(xué)習(xí)并使用 Spring Data JPA 可以極大提高開發(fā)效率坚俗!
spring data jpa讓我們解脫了DAO層的操作禽作,基本上所有CRUD都可以依賴于它來實現(xiàn)
簡單查詢
基本查詢也分為兩種尸昧,一種是spring data默認(rèn)已經(jīng)實現(xiàn),一種是根據(jù)查詢的方法來自動解析成SQL旷偿。
spring data jpa 默認(rèn)預(yù)先生成了一些基本的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();
}
自定義簡單查詢
Item findByItemName(String itemName);
List<Item> findByItemNameLike(String itemName);
Long deleteByItemId(Integer id);
List<Item> findByItemNameLikeOrderByItemNameDesc(String itemName);
具體的關(guān)鍵字,使用方法和生產(chǎn)成SQL如下表所示
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) |
分頁查詢
Page<Item> findALL(Pageable pageable);
@Test
public void test1() throws Exception {
int page=1,size=10;
Sort sort = new Sort(Sort.Direction.DESC, "id");//根據(jù)id降序排序
Pageable pageable = new PageRequest(page, size, sort);
Page<Item> pageResult = itemRepository.findALL(pageable);
List<Item> itemList = pageResult.getContent();
}
自定義SQL查詢
在SQL的查詢方法上面使用
@Query
注解尘喝,如涉及到刪除和修改在需要加上@Modifying
.也可以根據(jù)需要添加@Transactional
對事物的支持
//自定分頁查詢 一條查詢數(shù)據(jù),一條查詢數(shù)據(jù)量
@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注解
在自己實現(xiàn)的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寫對應(yīng)的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是怎么通過這些規(guī)范來進行組裝成查詢語句呢?
Spring Data JPA框架在進行方法名解析時无虚,會先把方法名多余的前綴截取掉缔赠,比如 find、findBy友题、read嗤堰、readBy、get度宦、getBy踢匣,然后對剩下部分進行解析。
假如創(chuàng)建如下的查詢:findByUserDepUuid()
戈抄,框架在解析該方法時离唬,首先剔除 findBy,然后對剩下的屬性進行解析
- 先判斷 userDepUuid (根據(jù) POJO 規(guī)范划鸽,首字母變?yōu)樾懀┦欠駷椴樵儗嶓w的一個屬性输莺,如果是戚哎,則表示根據(jù)該屬性進行查詢;如果沒有該屬性嫂用,繼續(xù)第二步型凳;
- 從右往左截取第一個大寫字母開頭的字符串此處為Uuid),然后檢查剩下的字符串是否為查詢實體的一個屬性嘱函,如果是啰脚,則表示根據(jù)該屬性進行查詢;如果沒有該屬性实夹,則重復(fù)第二步橄浓,繼續(xù)從右往左截取亮航;最后假設(shè)user為查詢實體的一個屬性荸实;
- 接著處理剩下部分(DepUuid),先判斷 user 所對應(yīng)的類型是否有depUuid屬性缴淋,如果有准给,則表示該方法最終是根據(jù)
Doc.user.depUuid
的取值進行查詢;否則繼續(xù)按照步驟 2 的規(guī)則從右往左截取重抖,最終表示根據(jù)Doc.user.dep.uuid
的值進行查詢露氮。 - 可能會存在一種特殊情況,比如 Doc包含一個 user 的屬性钟沛,也有一個 userDep 屬性畔规,此時會存在混淆『尥常可以明確在屬性之間加上 "_" 以顯式表達意圖叁扫,比如
findByUser_DepUuid()
或者findByUserDep_uuid()