Spring-Data-JPA 爬坑記
一: 實體類的常用註解
2.1 @Entity 標識這個 pojo 是一個 jpa 實體
2.2 @Table(name = "表名") 指定類對應的數據庫表名
2.3 @Id 標記某一字段為表主鍵
2.4 @GeneratedValue 標記主鍵生成策略
2.5 @Column 標記為字段,有如下屬性
2.5.1 name 對應數據庫的字段名,默認為 屬性名
2.5.2 unique 是否唯一,默認 false
2.5.3 nullable 是否可以為空 默認為 true
2.5.4 inserttable 是否可以插入,即提交 insert 語句時是否持久化的數據庫
2.5.5 updateable 是否可以跟新,即提交 update 語句時是否能修改該字段
2.5.6 length 字段長度
2.5.7 precision 和 scale 多少位數字,保留幾位小數
2.5.8 secondaryTable 從表名,該字段不在當前表,可以指定其它從表的名稱
2.5.9 columnDefinition 定義建表時創建此列的DDL,使用時,其它屬性將失效
2.5.9.1 columnDefinition="TEXT" 設置為文本類型
2.6 @Temporal(TemporalType.DATE) 設置為時間類型
2.6.1 TemporalType.DATE yyyy-mm-dd
2.6.2 TemporalType.TIME hh:mm:ss
2.6.3 TemporalType.TIMESTAMP yyyy-mm-dd hh:mm:ss
二: 持久層 @Repository
1,Repository<T, T> 基礎接口, 第一個 T 實體類 第二個T 主鍵類型 如 <User, Long>
1.1 提供了以方法名為查詢條件方法
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 (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<Age> ages) |
… where x.age in ?1 |
NotIn |
findByAgeNotIn(Collection<Age> 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) |
簡單的列子, 以上的 findBy 也可以改為 getBy 或者 readBy
package com.hwq.jpa.entity; import lombok.Getter; import lombok.Setter; import javax.persistence.*; @Entity @Setter @Getter public class Status { @Id @GeneratedValue @JoinColumn Long id; Long pId; @Column(length = 20) String name; }
package com.hwq.jpa.dao; import com.hwq.jpa.entity.Status; import org.springframework.data.repository.Repository; @org.springframework.stereotype.Repository // 註意兩個 Repository 不要沖突 public interface StatusDao extends Repository<Status, Long> { Status getById(Long id); // 根據 id Status 類 }
2, CrudRepository<T, T> 提供了簡單的增刪改查的方法, 繼承自 Repository<T, T>
3, PagingAndSortingRepository<T, T> 提供了分頁和排序的方法, 繼承自 CrudRepository<T, T>
4,JpaRepository<T, T> 繼承自 PagingAndSortingRepository<T, T>
5,JpaSpecificationExecutor<T> 條件查詢
簡單的例子,依然使用上面的實體類
package com.hwq.jpa.dao; import com.hwq.jpa.entity.Status; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; @Repository public interface StatusDao extends JpaRepository<Status, Long>, JpaSpecificationExecutor<Status> { }
package com.hwq.jpa.controller; import com.hwq.jpa.dao.StatusDao; import com.hwq.jpa.entity.Status; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.*; import org.springframework.data.domain.Sort.Order; import org.springframework.data.jpa.domain.Specification; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.persistence.criteria.*; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @RequestMapping("/status") public class StatusController { @Autowired StatusDao statusDao; @RequestMapping("/insert") public Status insert(Status status) { // 保存或者修改的方法 // 當存在主鍵時為修改,不存在為保存 return statusDao.save(status); } @RequestMapping("select") public Map<String, Object> select(Integer page, Integer size) { // 實例化 排序類, Sort 可以傳入多個 Order // Direction.DESC 降序 // Direction.ASC 升序 // "id" 排序字段 Order order1 = new Order(Direction.DESC, "id"); Sort sort = new Sort(order1); // 實例化分頁類 // page 查詢的當前頁數 // size 查詢的每一頁的最大記錄數 PageRequest pageAble = new PageRequest(page, size, sort); // 調用 findAll 方法 Page<Status> result = statusDao.findAll(pageAble); // 獲取需要的數據 Map<String, Object> map = new HashMap<String, Object>(); map.put("rows", result.getTotalElements()); // 獲取總記錄數 map.put("page", result.getNumber()); // 當前是第幾頁 map.put("pages", result.getTotalPages()); // 總共多少頁 map.put("data", result.getContent()); // 當前頁的數據 map.put("size", result.getNumberOfElements()); // 當前頁的記錄數 return map; } @RequestMapping("/select-if") public Map<String, Object> selectIf(Integer page, Integer size) { Order order1 = new Order(Direction.DESC, "id"); Sort sort = new Sort(order1); PageRequest pageAble = new PageRequest(page, size, sort); Specification<Status> statusSpecification = new Specification<Status>() { @Override public Predicate toPredicate(Root<Status> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Predicate predicate = null; // 最終返回的對象, 由 cb 創建 Path path = root.get("id"); // 定位到實體類的 id predicate = cb.gt(path, 1); // WHERE id > 1 return predicate; } }; // 調用 findAll 方法 Page<Status> result = statusDao.findAll(statusSpecification, pageAble); // 獲取需要的數據 Map<String, Object> map = new HashMap<String, Object>(); map.put("rows", result.getTotalElements()); // 獲取總記錄數 map.put("page", result.getNumber()); // 當前是第幾頁 map.put("pages", result.getTotalPages()); // 總共多少頁 map.put("data", result.getContent()); // 當前頁的數據 map.put("size", result.getNumberOfElements()); // 當前頁的記錄數 return map; } }
6,自定義的 Repository 方法《 註意以下三點 》《 無特殊情況,少用 》
6.1 必須創建一個任意的 接口 XxxDao
6.2 定義的 XxxRepository 繼承 XxxDao
6.3 實現 XxxDao 的類名稱必須為 XxxRepositoryImpl
6.3.1 實現類中可以使用 EntityManager 完美接入 JPA 的內容
簡單的例子, 依然使用最開始的實體類為
package com.hwq.jpa.repository.dao; import com.hwq.jpa.entity.Status; public interface StatusDao { Status selectStatusById(Long id); }
package com.hwq.jpa.repository; import com.hwq.jpa.entity.Status; import com.hwq.jpa.repository.dao.StatusDao; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Repository; @Repository public interface StatusRepository extends JpaRepository<Status, Long>, JpaSpecificationExecutor<Status>, StatusDao { }
package com.hwq.jpa.repository; import com.hwq.jpa.entity.Status; import com.hwq.jpa.repository.dao.StatusDao; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; public class StatusRepositoryImpl implements StatusDao { @PersistenceContext EntityManager entityManager; @Override public Status selectStatusById(Long id) { Status status = entityManager.find(Status.class, id); return status; } }
Spring-Data-JPA 爬坑記