Spring Data Jpa相關——JPA基本的查詢和修改方法
方法命名查詢
-
概述
根據方法的名字就能執行相對應的查詢語句,實現查詢。只需要按照Spring Data JPA提供的方法命名規則定義方法的 名稱,就可以完成查詢工作。Spring Data JPA在程序執行的時候會根據方法名稱進行解析,並自動生成查詢語句進行查詢 按照Spring Data JPA 定義的規則,查詢方法以 findBy 開頭,涉及條件查詢時,條件的屬性用條件關鍵字連接,要注意的是:條 件屬性首字母需大寫。框架在進行方法名解析時,會先把方法名多余的前綴截取掉,然后對剩下部分進行解析。
-
關鍵字
Keyword | Sample | JPQL |
---|---|---|
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 |
IsNull | findByAgeIsNull | … where x.age is null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
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
|
… where x.age in ?1 |
NotIn | findByAgeNotIn(Collection
|
… 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) |
方法命名查詢實際案例
-
實體類
@Entity
@Table(name = "tb_users")
@Setter
@Getter
@ToString
@NoArgsConstructor
public class User {
@Id
@GenericGenerator(name = "idGenerator", strategy = "uuid")
@GeneratedValue(generator = "idGenerator")
private String id;
@Column(name = "username", unique = true, nullable = false, length = 64)
private String username;
@Column(name = "password", nullable = false, length = 64)
private String password;
@Column(name = "email", length = 64)
private String email;
}
-
repository接口
@Repository
public interface UserRepository extends JpaRepository<User, String> {
//注意:方法的名稱必須要遵循駝峰式命名規則。xxxBy(關鍵字)+屬性名稱(首字母大寫)+查詢條件(首字母大寫)
/*** 根據用戶名精確查詢 *
* @param username *
* @return User
* */
User findByUsername(String username);
/*** 根據用戶名稱模糊查詢
* @param username
* @return User
*/
List<User> findByUsernameLike(String username);
}
-
測試類
@SpringBootTest
public class UserTest {
@Autowired
private UserRepository userRepository;
@Test
public void test1(){
User user = userRepository.findByUsername("zhangsan");
System.out.println(user);
}
@Test
public void test2(){
List<User> userList = userRepository.findByUsernameLike("%z%");
userList.forEach(System.out::println);
}
@Test
public void test3(){
List<User> userList = userRepository.findByUsernameLikeAndEmailLike("%z%", "%@qq.com");
userList.forEach(System.out::println);
}
}
注解式查詢
-
概述
使用Spring Data JPA提供的查詢方法已經可以解決大部分的應用場景,但是對於某些業務來說,我們還需要靈活的構造查詢條 件,這時就可以使用@Query注解,結合JPQL的語句方式完成查詢。
-
使用@query注解
(1)使用JPQL查詢
使用聲明式 JPQL 查詢有個好處,就是啟動的時候就知道你的語法正確不正確。JPQL一般只需要關心 @Query 里面的 value 和 nativeQuery
的值
案例:
repository接口
@Repository
public interface UserRepository extends JpaRepository<User, String> {
//單條件查詢
@Query("from User where username = ?1")
User gainUserByUsername(String username);
//多條件查詢
@Query("from User where username like %?1% and email like %?2")
List<User> gainUserListByUsernameAndEmail(String username, String email);
}
在JPQL中,用數字表示對應的位置參數,數字1對應第一個參數,在數字前要加一個?號表示這個數字為對應位置的參數。
測試方法
@Test
public void test4(){
User user = userRepository.gainUserByUsername("zhangsan");
System.out.println(user.getUsername());
List<User> userList = userRepository.gainUserListByUsernameAndEmail("zhang", ".com");
userList.forEach(System.out::println);
}
(2)使用原生的sql語句查詢
將@query注解中的nativeQuery設置為true
//使用原生的sql語句查詢
@Query(value = "select password from tb_users where email = ?1", nativeQuery = true)
String gainPasswdByEmail(String email);
參數位置同樣用?加數字來表示
-
@param注解的使用
默認情況下,參數是通過順序綁定在查詢語句上的,這使得查詢方法對參數位置的重構容易出錯。為了解決這個問題,可以使用 @Param 注解指定方法參數的具體名稱,通過綁定的參數名字做查詢條件,這樣不需要關心參數的順序,推薦這種做法,比較利於代碼重構
查詢方法
/*** 命名參數查詢 *
* @param username *
* @param address *
* @return */
@Query("from User where userName like :username% and address like %:address%")
List<User> findUserListByParam(@Param("username") String username,@Param("address") String address);
使用param注解之后,在查詢語句中使用':'+參數名的方式,來表示插入語句中的參數
測試方法
@Test
public void test6(){
List<User> userList = userRepository.findUserListByParam("z", "@");
userList.forEach(System.out::println);
}
-
@Modifying注解的使用
修改或者刪除的方法需要加上@Modifying注解,否則會報錯
修改方法
@Modifying
@Query("update User set username =?1 where id =?2")
int updateUser(String username,String id);
刪除方法
@Modifying
@Query("delete from User where id =?1")
int deleteUser(String id);
測試
@Test
@Transactional
@Rollback(false)
public void test7(){
if(userRepository.findById("40281d817c6d6def017c6d6dfb0a0000").isPresent()){
System.out.println(userRepository.findById("40281d817c6d6def017c6d6dfb0a0000").get());
if(userRepository.updateUser("hahaha", "40281d817c6d6def017c6d6dfb0a0000") > 0)
System.out.println("用戶名修改成功");
}
}
@Test
@Transactional
@Rollback(false)
public void test8(){
if(userRepository.deleteUser("40281d817c6deb53017c6deb60b20AEEC") > 0)
System.out.println("刪除成功");
else
System.out.println("刪除失敗,用戶可能不存在");
}
測試的時候需要開啟事務不然會報錯,然后要把回滾關閉,不然的話執行完方法就會自動回滾
-
@query注解查詢的優點
-
可以靈活快速的使用 JPQL 和 SQL
-
對返回的結果和字段可以自定義
-
支持連表查詢和對象關聯查詢,可以組合出來復雜的 SQL 或者 JPQL
-
可以很好的表達你的查詢思路
-
靈活性非常強,快捷方便
-
@query注解查詢的缺點
-
不支持動態查詢條件,參數個數如果是不固定的不支持
-
若將返回結果用 Map 或者 Object[] 數組接收結果,會導致調用此方法的開發人員不知道返回結果里面到底有些什么數據