Spring Data JPA - 中文手冊(cè)
參考文檔:
http://blog.csdn.net/liuchuanhong1/article/details/70244261?utm_source=gold_browser_extension
https://docs.spring.io/spring-data/jpa/docs/1.11.9.RELEASE/reference/html/#specifications
https://www.v2ex.com/t/350737
項(xiàng)目中使用spring data jpa
@EnableJpaRepositories
class Config {}
查詢方法的生成策略 Query lookup strategies
- CREATE 根據(jù)方法的名字直接創(chuàng)建對(duì)應(yīng)的查詢語(yǔ)句
- USE_DECLARED_QUERY 使用聲明的查詢語(yǔ)句了罪,如果每一找到聲明的語(yǔ)句將會(huì)拋出一個(gè)異常泊藕,聲明一個(gè)語(yǔ)句使用
@NamedQuery
- CREATE_IF_NOT_FOUND 首先查找是否已經(jīng)有聲明的查詢語(yǔ)句娃圆,如果每一再創(chuàng)建蛾茉,這是默認(rèn)的策略
通過(guò)方法名來(lái)定義語(yǔ)句
public interface PersonRepository extends Repository<User, Long> {
// 使用 distinct 關(guān)鍵字
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
// 忽略大小寫(xiě)進(jìn)行匹配 IgnoreCase
List<Person> findByLastnameIgnoreCase(String lastname);
// 對(duì)所有的查詢條件進(jìn)行忽略大小寫(xiě)進(jìn)行匹配 IgnoreCase
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
// Order By 語(yǔ)句
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
//Person 中有個(gè)Address, Address中有zipCode屬性悦屏,直接通過(guò)zipCode來(lái)查詢Persion
List<Person> findByAddressZipCode(ZipCode zipCode);
//和上面的方法完成同樣的功能础爬, 使用 _ 可以用來(lái)區(qū)分屬性,避免生成錯(cuò)誤的語(yǔ)句
List<Person> findByAddress_ZipCode(ZipCode zipCode);
//限制返回?cái)?shù)據(jù)的條數(shù) Limiting query results
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
//異步查詢,調(diào)用查詢方法后立即返回 Async query results
@Async
Future<User> findByFirstname(String firstname);
@Async
CompletableFuture<User> findOneByFirstname(String firstname);
@Async
ListenableFuture<User> findOneByLastname(String lastname);
}
為所有生成的Repository添加一些額外的方法
1. 聲明一個(gè)接口常熙,定義出需要添加的方法
@NoRepositoryBean
public interface MyRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID> {
void sharedCustomMethod(ID id);
}
2. 實(shí)現(xiàn)定義的接口
public class MyRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
private final EntityManager entityManager;
public MyRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
// Keep the EntityManager around to used from the newly introduced methods.
this.entityManager = entityManager;
}
public void sharedCustomMethod(ID id) {
// implementation goes here
}
}
3.配置實(shí)現(xiàn)類
@Configuration
@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }
Web support
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration { }
@EnableSpringDataWebSupport
將會(huì)開(kāi)啟一些組件,具體可以打開(kāi)源碼查看
PageableHandlerMethodArgumentResolver
通過(guò)參數(shù)可以自動(dòng)注入Pageable
對(duì)象到控制器
page -> Page you want to retrieve, 0 indexed and defaults to 0. |
size -> Size of the page you want to retrieve, defaults to 20. |SortHandlerMethodArgumentResolver
通過(guò)參數(shù)可以自動(dòng)注入Sort
對(duì)象到控制器
sort -> Properties that should be sorted by in the format property,property(,ASC|DESC). Default sort direction is ascending. Use multiple sort parameters if you want to switch directions, e.g. ?sort=firstname&sort=lastname,asc. |DomainClassConverter
傳入一個(gè)對(duì)象Id 就可以直接轉(zhuǎn)換成 需要對(duì)象
@Controller
@RequestMapping("/users")
public class UserController {
@Autowired UserRepository repository;
@RequestMapping
public String showUsers(Model model, Pageable pageable) {
model.addAttribute("users", repository.findAll(pageable));
return "users";
}
}
如果在需要注入對(duì)個(gè)Pageable對(duì)象到controller中,可以使用@Qualifier
來(lái)定義前綴聋袋,下劃線分隔穴吹,eg: foo_page=1
public String showUsers(Model model,
@Qualifier("foo") Pageable first,
@Qualifier("bar") Pageable second) { … }
@PageableDefault
配置默認(rèn)的分頁(yè)港令,如果前端沒(méi)有傳入分頁(yè)信息顷霹,可以使用來(lái)設(shè)置默認(rèn)的分頁(yè)淋淀,默認(rèn)是 new PageRequest(0, 20)
Supported keywords inside method names
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> ages) | … 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) |
使用@Query
來(lái)聲明語(yǔ)句
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
nativeQuery = true)
Page<User> findByLastname(String lastname, Pageable pageable);
}
Using SpEL expressions
public interface UserRepository extends JpaRepository<User,Long> {
@Query("select u from #{#entityName} u where u.lastname = ?1")
List<User> findByLastname(String lastname);
}
entityName
表示實(shí)體類的名字
使用查詢提示徽缚,具體的查詢提示的值是根據(jù)JPA底層實(shí)習(xí)框架提供的
public interface UserRepository extends Repository<User, Long> {
@QueryHints(value = { @QueryHint(name = "name", value = "value")},
forCounting = false)
Page<User> findByLastname(String lastname, Pageable pageable);
}
自定義查詢返回的返回結(jié)果
1. 通過(guò)定義接口的方式來(lái)返回?cái)?shù)據(jù)
假如實(shí)體對(duì)象:
class Person {
@Id UUID id;
String firstname, lastname;
Address address;
static class Address {
String zipCode, city, street;
}
}
可以這樣定義一個(gè)接口:
interface PersonSummary {
String getFirstname();
String getLastname();
AddressSummary getAddress();
interface AddressSummary {
String getCity();
}
}
查詢方法的定義:
interface PersonRepository extends Repository<Person, UUID> {
Collection<PersonSummary> findByLastname(String lastname);
}
這樣就可以完成自定義查詢凿试,還有其他方式定義接口
interface NamesOnly {
@Value("#{target.firstname + ' ' + target.lastname}")
String getFullName();
…
}
組合了firstname
lastname
, 返回的對(duì)象將會(huì)用 target
變量替代那婉。如果想要做更加復(fù)雜的編程可以使用下面的方法详炬,使用default定義一個(gè)方法
interface NamesOnly {
String getFirstname();
String getLastname();
default String getFullName() {
//定義自己的邏輯實(shí)現(xiàn),可以通過(guò)ApplicationContext 來(lái)獲取bean對(duì)象來(lái)調(diào)用方法
return getFirstname.concat(" ").concat(getLastname());
}
}
調(diào)用容器中的Bean來(lái)返回結(jié)果的另一種方式@myBean
@Component
class MyBean {
String getFullName(Person person) {
…
}
}
interface NamesOnly {
@Value("#{@myBean.getFullName(target)}")
String getFullName();
…
}
如果想要使用 方法中的參數(shù)可以用這種方式
interface NamesOnly {
@Value("#{args[0] + ' ' + target.firstname + '!'}")
String getSalutation(String prefix);
}
args[i]
i 表示方法中的第幾個(gè)
2. 通過(guò)定義DTO的方式來(lái)返回?cái)?shù)據(jù)
這種方式底層會(huì)根據(jù)DTO暴露的構(gòu)造放的參數(shù)名字來(lái)加載 需要的字段
定義的DTO
class NamesOnly {
private final String firstname, lastname;
NamesOnly(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
String getFirstname() {
return this.firstname;
}
String getLastname() {
return this.lastname;
}
// equals(…) and hashCode() implementations
}
定義的Repository
interface PersonRepository extends Repository<Person, UUID> {
Collection<T> findByLastname(String lastname, Class<T> type);
}
使用方式如下:
void someMethod(PersonRepository people) {
Collection<Person> aggregates = people.findByLastname("Matthews", Person.class);
Collection<NamesOnly> aggregates = people.findByLastname("Matthews", NamesOnly.class);
}
存儲(chǔ)過(guò)程的使用
參考:https://docs.spring.io/spring-data/jpa/docs/1.11.9.RELEASE/reference/html/#jpa.stored-procedures
Specifications
public class CustomerSpecs {
public static Specification<Customer> isLongTermCustomer() {
return new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
LocalDate date = new LocalDate().minusYears(2);
return builder.lessThan(root.get(_Customer.createdAt), date);
}
};
}
public static Specification<Customer> hasSalesOfMoreThan(MontaryAmount value) {
return new Specification<Customer>() {
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
// build query here
}
};
}
}
List<Customer> customers = customerRepository.findAll(isLongTermCustomer());
Locking
interface UserRepository extends Repository<User, Long> {
// Plain query method
@Lock(LockModeType.READ)
List<User> findByLastname(String lastname);
}
Auditing
提供的注解猫妙,在實(shí)體中添加:
@CreatedBy
, @LastModifiedBy
, @CreatedDate
, @LastModifiedDate
實(shí)現(xiàn)接口AuditorAware
為 @CreatedBy
, @LastModifiedBy
設(shè)置值
class SpringSecurityAuditorAware implements AuditorAware<User> {
public User getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
return ((MyUserDetails) authentication.getPrincipal()).getUser();
}
}
最后在實(shí)體上添加注解@EntityListeners(AuditingEntityListener.class)
@Entity
@EntityListeners(AuditingEntityListener.class)
public class MyEntity {
}
獲取 EntityManager
對(duì)象
可以使用@PersistenceContext
. spring data jpa 還提供了一種方式:
class UserRepositoryImpl implements UserRepositoryCustom {
private final EntityManager em;
@Autowired
public UserRepositoryImpl(JpaContext context) {
this.em = context.getEntityManagerByManagedType(User.class);
}
}
https://docs.spring.io/spring-data/jpa/docs/1.11.9.RELEASE/reference/html/#appendix
更多spring 相關(guān)文章:
http://blog.xianshiyue.com/tag/springboot/
http://blog.xianshiyue.com/tag/spring-cloud/
http://blog.xianshiyue.com/tag/springmvc/