上一節(jié)已經(jīng)準(zhǔn)備好了數(shù)據(jù)庫(kù),建好了實(shí)體,現(xiàn)在就來(lái)具體操作數(shù)據(jù)庫(kù)
SpringBoot JPA異常簡(jiǎn)單,只需要在dao層建一個(gè)接口,再繼承JpaRepository就可以快速進(jìn)行CURD操作了,你只需要聲明接口,都不需要寫(xiě)實(shí)現(xiàn),一切都交給SpringBoot來(lái)完成,簡(jiǎn)單到無(wú)話可說(shuō),直接上例子。
public interface ArticleRepository extends JpaRepository<Article,String> {
//根據(jù)ID查詢文章
public Article getById(String id);
//根據(jù)作者和狀態(tài)查詢文章列表
public List<Article> findByAuthorAndStatus(String author,int status);
//分頁(yè)查詢數(shù)據(jù)文章
public Page<Article> findByStatus(int status,Pageable pageable);
//分頁(yè)搜索,自己寫(xiě)jpql語(yǔ)句
@Query("select a from Article a where a.title like ?1 or a.content like ?1")
public Page<Article> search(String keys, Pageable page);
//原生sql查詢
@Query(value = "select * from article from title =?1 and status=1 order by tm desc ",nativeQuery =true)
public List<Article> finddata(String title);
//更新操作,指定參數(shù)名
@Modifying
@Transactional(readOnly = false)
@Query("update Article a set a.status = :status ")
int setStatus(@Param("status") int status);
}
下面是service層調(diào)用的代碼
@Service
public class ArticleService {
@Autowired
private ArticleRepository articleRepository;
/**
* 保存文章
*/
public void saveArticle(){
Article article=new Article();
article.setId(UUID.randomUUID().toString());
article.setTitle("新的文章");
article.setContent("文章內(nèi)容,僅做測(cè)試!");
article.setAuthor("佚名");
article.setTm(new Date());
article.setSystm(new Date());
article.setStatus(1);
articleRepository.save(article);
}
/**
* 根據(jù)ID查詢文章
* @param id 文章ID
* @return
*/
public Article getById(String id){
return articleRepository.getById(id);
}
/**
* 查詢作者發(fā)布的文章
* @param author 作者
* @return
*/
public List<Article> findArticlesByAuthor(String author){
return articleRepository.findByAuthorAndStatus(author,1);
}
/**
* 列表分頁(yè)數(shù)據(jù)查詢
* @param page 頁(yè)碼
* @param size 數(shù)量
* @return
*/
public Page<Article> findIndexData(int page,int size){
Pageable pageable= PageRequest.of(page, size, Sort.by(Sort.Direction.DESC,"tm"));
Page<Article> pagedata=articleRepository.findByStatus(1,pageable);
return pagedata;
}
/**
* 根據(jù)標(biāo)題或內(nèi)容關(guān)鍵字搜索,返回分頁(yè)數(shù)據(jù)
* @param keys 關(guān)鍵字
* @param page 分頁(yè)信息
* @return
*/
public Page<Article> search(String keys, int page,int size){
Pageable pageable= PageRequest.of(page, size, Sort.by(Sort.Direction.DESC,"tm"));
Page<Article> pagedata=articleRepository.search("%"+keys+"%",pageable);
return pagedata;
}
}
一切近乎完美,就是這么簡(jiǎn)單,可以完全不需要寫(xiě)任何sql,不需要寫(xiě)任何實(shí)現(xiàn),僅僅只需要定義一個(gè)接口,SpringBoot會(huì)自動(dòng)根據(jù)方法名幫你實(shí)現(xiàn)。當(dāng)然你也可以通過(guò)@Query注解自定義sql,這個(gè)sql是jpql語(yǔ)句,如果是原生sql查詢,設(shè)置nativeQuery =true即可。修改更新時(shí)需要加@Modifying注解
以下是我在Spring Data JPA 文檔中找到的命名規(guī)則表:
| 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) |
@Transactional 事務(wù)支持說(shuō)明
默認(rèn)情況下,Springboot JPA 實(shí)現(xiàn)的方法都是使用事務(wù)的。針對(duì)查詢類型的方法,其等價(jià)于 @Transactional(readOnly=true);增刪改類型的方法,等價(jià)于 @Transactional??梢钥闯?,除了將查詢的方法設(shè)為只讀事務(wù)外,其他事務(wù)屬性均采用默認(rèn)值。
如果用戶覺(jué)得有必要,可以在接口方法上使用 @Transactional 顯式指定事務(wù)屬性,該值覆蓋 Springboot JPA 提供的默認(rèn)值。同時(shí),開(kāi)發(fā)者也可以在業(yè)務(wù)層方法上使用 @Transactional 指定事務(wù)屬性,這主要針對(duì)一個(gè)業(yè)務(wù)層方法多次調(diào)用持久層方法的情況。持久層的事務(wù)會(huì)根據(jù)設(shè)置的事務(wù)傳播行為來(lái)決定是掛起業(yè)務(wù)層事務(wù)還是加入業(yè)務(wù)層的事務(wù)。