[JAVA EE] JPA 查询用法:自定义查询,分页查询
項目已上傳:https://codechina.csdn.net/qq_36286039/javaee
自定義查詢
問題:內置的crud功能不滿足需求時如何添加自定義查詢?
幾種自定義查詢方法
- 方法命名規則查詢
- 按照 JPA 定義的規則,查詢方法以
find|read|get開頭(比如 find、findBy、read、readBy、get、getBy),涉及條件查詢時,條件的屬性用條件關鍵字連接, - 注意:條件屬性首字母需大寫。
- JPA 框架在進行方法名解析時,會先把方法名多余的前綴截取掉,然后對
剩下部分進行解析,最后會自動創建查詢。 - 示例:
findByUsernameAndPassword(String name, String pwd)findByUsernameLike(String name)
詳細的方法命名規則
- JPQL 查詢 – JPA Query Language
- JPQL和SQL很像,查詢關鍵字都是一樣的,主要區別是:JPQL 是面向對象的,是針對實體類進行的操作,即將數據庫表名、列名等信息替換為實體類對象及其屬性(區分大小寫)。
- JPQL 語句可以是 select 語句、update 語句或 delete 語句。
- 常用
@Query注解。
JPQL 示例
@Transactional 是聲明式事務管理編程中使用的注解.
涉及到數據修改操作,可以使用 @Modifying 注解, @Query 與 @Modifying 這兩個 annotation一起聲明,可定義個性化更新操作
- 示例1:查詢所有
@Query("select u from User u")
public List<User> findAllUser();
- 示例2:條件查詢
@Query("select u from User u where u.id = ?1")
//或
@Query("select u from User u where u.id = :id")
public User getUserById(long id);
- 示例3:update操作
@Transactional
@Modifying
@Query("update User u set u.username = ?1 where u.id = ?2")
int updateUsernameById(String username, Long id);
- 原生 SQL 查詢
- 使用 @Query 注解,value參數寫SQL語句,nativeQuery參數為 true。
- 示例1:
@Query(value = "select * from user where id = ?1", nativeQuery = true)
public User getUserById2(Long id);
- 示例2:
@Transactional
@Modifying
@Query(value="update user set username = ?1 where id = ?2", nativeQuery = true)
int updateUsernameById2(String username, Long id);
實操演練:
方法命名規則查詢示例
UserRepository.java里添加
// 只需按JPA指定規則寫出方法名即可,JPA會自動生成 SQL (太強大了)// 方法名常見規則:findByXX, countByXX XX為屬性名,例如:public User findByUsername(String username); //根據username精確查找public List<User> findByUsernameLike(String s); //查詢username中包含s串的user,需要手工加%public List<User> findByUsernameContaining(String s); //查詢username中包含s串的user,無需加%public List<User> findByRegdateAfter(Date mydate); //查詢在mydate日期之后注冊的userpublic Long countByUsernameContaining(String s); //count是統計查詢結果的總數public List<User> findByIdLessThanEqualOrderByUsernameDesc(Long id);//查詢id值小于等于某個值,且按username降序排序
新建一個TestController.java
說明:
3L其實就是3。
java中經常會碰到“long c = 1L”的寫法,L表示long ,long占用8個字節,表示范圍:-9223372036854775808 ~ 9223372036854775807
常量后面跟這個一般是指類型,1L表示1是長整型,如果是1f 表示是float型
package com.example.jpademo2.controller;import com.example.jpademo2.entity.User;
import com.example.jpademo2.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;@RestController
public class TestController {@Autowiredprivate UserRepository userRepository;@RequestMapping("/testuser1")public User test1() {User user = userRepository.findByUsername("admin");return user;}//查找username包含"m"串的用戶@RequestMapping("/testuser2")public List<User> test2() {//需要手動添加“%”List<User> users = userRepository.findByUsernameLike("%m%");return users;}//查找username包含"m"串的用戶@RequestMapping("/testuser3")public List<User> test3() {List<User> users = userRepository.findByUsernameContaining("m");return users;}//查詢在mydate日期之后注冊的user@RequestMapping("/testuser4")public List<User> test4() throws ParseException {SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date myDate = df.parse("2020-10-1 23:59:59");List<User> users = userRepository.findByRegdateAfter(myDate);return users;}//統計username包含"m"的用戶個數@RequestMapping("/testuser5")public Long test5() {return userRepository.countByUsernameContaining("m");}//查詢id值小于等于3L,且按username降序排序@RequestMapping("/testuser6")public List<User> test6() {List<User> users = userRepository.findByIdLessThanEqualOrderByUsernameDesc(3L);return users;}
}
用postman測試一下
當前數據庫:
http://localhost:8080/testuser1:找admin
http://localhost:8080/testuser2:找用戶名包含m的用戶
http://localhost:8080/testuser3:找用戶名包含m的用戶
http://localhost:8080/testuser4:找Mydate之后注冊的用戶
http://localhost:8080/testuser5:統計username包含"m"的用戶個數(2個)
http://localhost:8080/testuser6:查詢id值小于等于3L,且按username降序排序
JPQL 查詢示例
在UserRepository.java 中添加
//JPQL 查詢示例@Transactional@Modifying@Query("update User u set u.username = ?1 where u.id = ?2")int updateUsernameById(String username, Long id);@Query(value = "select * from user where id = ?1", nativeQuery = true)public User getUserById2(long id);@Transactional@Modifying@Query(value="update user set username = ?1 where id = ?2", nativeQuery = true)int updateUsernameById2(String username, Long id);
在TestController.java中添加
//找所有@RequestMapping("/testuser7")public List<User> test7() {List<User> users = userRepository.findAllUser();return users;}//找id為2的User@RequestMapping("/testuser8")public User test8() {User user = userRepository.getUserById(2L);return user;}//更新Id為2的username@RequestMapping("/testuser9")public int test9() {int count= userRepository.updateUsernameById("dustId2",2L);return count;}
使用postman測試:
username被修改了之后在試試
原生 SQL 查詢示例
UserRepository.java 中添加
//原生SQL查詢示例@Query(value = "select * from user where id = ?1", nativeQuery = true)public User getUserById2(long id);@Transactional@Modifying@Query(value="update user set username = ?1 where id = ?2", nativeQuery = true)int updateUsernameById2(String username, Integer id);
TestController里添加
//找id為2的User@RequestMapping("/testuser10")public User test10() {return userRepository.getUserById2(2L);}//更新Id為2的username@RequestMapping("/testuser11")public int test11() {int count= userRepository.updateUsernameById2("dust@qq.com",2);return count;}
使用postman測試:
分頁查詢
- JPA 在查詢的方法中傳入參數 Pageable 對象 來實現分頁功能,通過該參數可得到和分頁相關的所有信息。
- 有多個參數時,Pageable 作為最后一個參數
page:第幾頁,從0開始,默認為第0頁
size:每一頁的大小,默認為20
sort:排序方式
- Pageable 對象創建方法 :
Pageable pageable = PageRequest.of( page, size, sort );- sort定義示例:按 id 升序排序
Sort sort = Sort.by(Sort.Direction.ASC, "id");
- 查詢方法返回 Page ,可以得到數據的總體信息(如數據總數、總頁數
等)以及當前頁數據的信息(當前數據的集合、當前頁數等): - Page 對象相關方法
| 方法名 | 功能 |
|---|---|
| List getContent(); | 將所有數據返回為List |
| boolean hasContent(); | 返回數據是否有內容。 |
| int getNumber() | 當前第幾頁(從0開始),總是非負的 |
| int getTotalPages() | 返回分頁總數 |
| long getTotalElements() | 返回元素總數 |
| boolean hasPreviousPage() | 如果有上一頁。 |
| boolean hasNextPage() | 如果有下一頁 |
| boolean isFirstPage() | 當前頁是否為第一頁。 |
| boolean isLastPage() | 當前頁是否為最后一頁。 |
| int getSize() | 返回當前頁面的大小。 |
| Sort getSort() | 返回頁的排序參數。 |
| int getNumberOfElements() | 返回當前頁上的元素數。 |
分頁查詢示例:
UserRepository.java中添加:
//自定義分頁查詢//import org.springframework.data.domain.Page;//import org.springframework.data.domain.Pageable;//這里很容易引入錯誤的包public Page<User> findAllBy(Pageable pageable);//在查詢的方法中傳入 Pageable 參數public Page<User> findByUsernameContaining(String username,Pageable pageable);//有多個參數時,Pageable 作為最后一個參數
TestController.java中添加:
@RequestMapping("/testuser12")public Page<User> test12() {Sort sort = Sort.by(Sort.Direction.ASC, "id"); //id升序排序Pageable pageable = PageRequest.of( 0, 10, sort ); // 第0頁,每一頁10個Page<User> page = userRepository.findAll( pageable );return page; //返回結果見下頁}@RequestMapping("/testuser13")public List<User> test13() {Sort sort = Sort.by(Sort.Direction.DESC, "username"); //username降序排序Pageable pageable = PageRequest.of( 0, 10, sort ); // 第0頁,每一頁10個Page<User> page = userRepository.findAll( pageable );List<User> list = page.getContent(); //得到 List 數據return list; //返回List<User>}
分頁查詢示例2:
服務層:UserService 接口層
package com.example.jpademo2.service;import com.example.jpademo2.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;import java.util.List;//服務層接口
public interface UserService {//根據也無需要定義業務功能接口方法public List<User> getUserList();public User findUserById(Long id);public void save(User user);public void edit(User user);public void delete(Long id);// 添加兩個分頁業務功能接口public Page<User> getUserList(Pageable pageable);public Page<User> getUserListByUsername(String username,Pageable pageable);
}
服務層:UserServiceImp 實現
package com.example.jpademo2.service;import com.example.jpademo2.entity.User;
import com.example.jpademo2.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;import java.util.List;//實現服務層接口
@Service
public class UserServiceImp implements UserService{@Autowiredprivate UserRepository userRepository;@Overridepublic List<User> getUserList(){return userRepository.findAll();//直接調用Repository內置的CURD方法}@Overridepublic User findUserById(Long id){return userRepository.findById(id).get();//直接調用Repository內置的CURD方法//findById(id)返回的是Optional類(一個可以為null的容器對象)//如果Optional容器中存在對象,則調用get()方法返回該對象}@Overridepublic void edit(User user){userRepository.save(user);//直接調用Repository內置的CURD方法}@Overridepublic void save(User user){userRepository.save(user);//直接調用Repository內置的CURD方法}@Overridepublic void delete(Long id){userRepository.deleteById(id);//直接調用Repository內置的CURD方法}// 實現兩個分頁業務@Overridepublic Page<User> getUserList(Pageable pageable) {return userRepository.findAll(pageable);}@Overridepublic Page<User> getUserListByUsername(String username,Pageable pageable) {return userRepository.findByUsernameContaining(username,pageable);}}
控制器層:修改的 list 方法
參數說明:實際傳遞的只有 page,size這兩個參數。model和request為系統參數
用了 session 存儲"return_url"
@RequestMapping("/list")public String list(Model model, HttpServletRequest request, @RequestParam(value="page",defaultValue="0")Integer page, @RequestParam(value="size", defaultValue="5")Integer size) {if (page==null || page<=0) { page = 1; } // 將第0頁轉換為習慣的第1頁if (size==null || size<=0) { size = 5; }Sort sort = Sort.by(Sort.Direction.ASC, "id"); // 排序字段是實體類的屬性Pageable pageable = PageRequest.of(page - 1, size, sort); // (當前頁,每頁記錄數,排序方式)Page<User> users = userService.getUserList(pageable);model.addAttribute("users", users);model.addAttribute("size", size);request.getSession().setAttribute("return_url", request.getServletPath()+"?"+request.getQueryString());//新建編輯刪除中返回的urlreturn "user/list";}
視圖層:修改 list.html
說明:后臺傳來的 users 是
Page<User>通過getContent()可得到List<User>
<tr th:each="user : ${ users.getContent() }">
<!--添加分頁,放在 table 標簽后-->
<div th:replace="/common/page :: page1"></div>
修改 add.html、edit.html、delete.html 的所有 “返回” 鏈接
將原來的
th:href = "@{/list}"全部修改為th:href = "@{${session.return_url}}"
<a th:href = "@{${session.return_url}}">返回</a>
fragement布局視圖:page.html
在 templates 中新建 common 目錄,并創建 page.html。
page.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Page</title>
</head>
<body>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div class="container" th:fragment="page1"><div style="text-align: right;"><div>當前第<span th:text="${users.getNumber()} + 1"></span>頁 /總<span th:text="${users.getTotalPages()}"></span>頁共<span th:text="${users.getTotalElements()}"></span>條記錄<a class="btn btn-info" th:href="@{/list(page=1,size=${size})}">首頁</a><a class="btn btn-info"th:href="@{/list(page = ${users.hasPrevious()} ? ${users.getNumber()} : 1,size=${size})}">上一頁</a><a class="btn btn-info"th:href="@{/list(page = ${users.hasNext()} ? ${users.getNumber()} + 2 : ${users.getTotalPages()},size=${size})}">下一頁</a><a class="btn btn-info" th:href="@{/list(page = ${users.getTotalPages()},size=${size})}">尾頁</a></div></div>
</div>
</body>
</html>
</body>
</html>
運行結果:
總結
以上是生活随笔為你收集整理的[JAVA EE] JPA 查询用法:自定义查询,分页查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [JS] undefined、null、
- 下一篇: DOM相关内容(课程来源:B站 后盾人)