計算 Spring Data JPA 中的行數
1. 概述
Spring Data JPA 實現為 Jakarta Persistence API 提供存儲庫支持,用於管理持久性和對象關係映射和函數。
在本文中,我們將探索使用 JPA 計算表中行數的不同方法。
2.實體類
對於我們的示例,我們將使用Account
實體,它與Permission
實體具有一對一的關係。
@Entity
@Table(name="ACCOUNTS")
public class Account {
@Id
@GeneratedValue(strategy= GenerationType.SEQUENCE, generator = "accounts_seq")
@SequenceGenerator(name = "accounts_seq", sequenceName = "accounts_seq", allocationSize = 1)
@Column(name = "user_id")
private int userId;
private String username;
private String password;
private String email;
private Timestamp createdOn;
private Timestamp lastLogin;
@OneToOne
@JoinColumn(name = "permissions_id")
private Permission permission;
// getters , setters
}
Permission
屬於賬戶實體。
@Entity
@Table(name="PERMISSIONS")
public class Permission {
@Id
@GeneratedValue(strategy= GenerationType.SEQUENCE, generator = "permissions_id_sq")
@SequenceGenerator(name = "permissions_id_sq", sequenceName = "permissions_id_sq", allocationSize = 1)
private int id;
private String type;
// getters , setters
}
3.使用JPA存儲庫
Spring Data JPA 提供了一個可擴展的存儲庫接口,它提供了開箱即用的查詢方法和派生查詢方法,例如findAll()
,
findBy()
,
save(),
saveAndFlush()
,
count()
,
countBy()
,
delete()
,
deleteAll()
.
我們將定義擴展JpaRepository
接口的AccountRepository
接口,以便可以訪問count
方法。
如果我們需要基於一個或多個條件進行計數,例如countByFirstname()
、 countByPermission(),
或countByPermissionAndCredtedOnGreaterThan()
,我們只需要AccountRepository
接口中的方法名稱,查詢派生將負責為以下對象定義適當的 SQL:它。
public interface AccountRepository extends JpaRepository<Account, Integer> {
long countByUsername(String username);
long countByPermission(Permission permission);
long countByPermissionAndCreatedOnGreaterThan(Permission permission, Timestamp ts)
}
在下面的示例中,我們將使用邏輯類中的AccountRepository來執行計數操作。
3.1.計算表中的所有行數
我們將定義一個邏輯類,在其中註入AccountRepository,
對於簡單的 row count() operation,
我們可以只使用accountRepository.count() **,**
我們就會得到結果。
@Service
public class AccountStatsLogic {
@Autowired
private AccountRepository accountRepository;
public long getAccountCount(){
return accountRepository.count();
}
}
3.2.根據單一條件計算結果行數
正如我們上面所定義的, AccountRepository
包含countByPermission
和countByUsername,
Spring Data JPA 查詢派生將派生這些方法的查詢。
所以我們可以在邏輯類中使用這些方法進行條件計數,我們就會得到結果。
@Service
public class AccountStatsLogic {
@Autowired
private AccountRepository accountRepository;
@Autowired
private PermissionRepository permissionRepository;
public long getAccountCountByUsername(){
String username = "user2";
return accountRepository.countByUsername(username);
}
public long getAccountCountByPermission(){
Permission permission = permissionRepository.findByType("reader");
return accountRepository.countByPermission(permission);
}
}
3.3.根據多個條件統計結果行數
我們還可以在查詢派生中包含多個條件,如下所示,其中包含Permission
和CreatedOnGreaterThan
.
@Service
public class AccountStatsLogic {
@Autowired
private AccountRepository accountRepository;
@Autowired
private PermissionRepository permissionRepository;
public long getAccountCountByPermissionAndCreatedOn() throws ParseException {
Permission permission = permissionRepository.findByType("reader");
Date parsedDate = getDate();
return accountRepository.countByPermissionAndCreatedOnGreaterThan(permission, new Timestamp(parsedDate.getTime()));
}
}
4. 使用 CriteriaQuery
在 JPA 中計算行數的下一個方法是使用CriteriaQuery
接口。這個接口允許我們以面向對象的方式編寫查詢,這樣我們就可以跳過編寫原始 SQL 查詢的知識。
它要求我們構造一個CriteriaBuilder
對象,然後它幫助我們構造CriteriaQuery
.
CriteriaQuery
準備就緒後,我們可以使用entityManager
中的createQuery
方法來執行查詢並獲取結果。
4.1.計算所有行數
現在,當我們使用CriteriaQuery
構造查詢時,我們可以定義要計數的選擇查詢,如下所示。
public long getAccountsUsingCQ() throws ParseException {
// creating criteria builder and query
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
Root<Account> accountRoot = criteriaQuery.from(Account.class);
// select query
criteriaQuery.select(builder.count(accountRoot));
// execute and get the result
return entityManager.createQuery(criteriaQuery).getSingleResult();
}
4.2.根據單一條件統計結果行數
我們還可以擴展 select 查詢以包含 where 條件,以根據某些條件過濾我們的查詢。我們可以向構建器實例添加一個Predicate
並將其傳遞給where
子句。
public long getAccountsByPermissionUsingCQ() throws ParseException {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
Root<Account> accountRoot = criteriaQuery.from(Account.class);
List<Predicate> predicateList = new ArrayList<>(); // list of predicates that will go in where clause
predicateList.add(builder.equal(accountRoot.get("permission"), permissionRepository.findByType("admin")));
criteriaQuery
.select(builder.count(accountRoot))
.where(builder.and(predicateList.toArray(new Predicate[0])));
return entityManager.createQuery(criteriaQuery).getSingleResult();
}
4.3.根據多個條件統計結果行數
在我們的謂詞中,我們可以添加多個條件來過濾我們的查詢。構建器實例提供了equal()
和greaterThan
()
等條件方法來支持查詢條件。
public long getAccountsByPermissionAndCreateOnUsingCQ() throws ParseException {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
Root<Account> accountRoot = criteriaQuery.from(Account.class);
List<Predicate> predicateList = new ArrayList<>();
predicateList.add(builder.equal(accountRoot.get("permission"), permissionRepository.findByType("reader")));
predicateList.add(builder.greaterThan(accountRoot.get("createdOn"), new Timestamp(getDate().getTime())));
criteriaQuery
.select(builder.count(accountRoot))
.where(builder.and(predicateList.toArray(new Predicate[0])));
return entityManager.createQuery(criteriaQuery).getSingleResult();
}
5.使用JPQL查詢
執行計數的下一個方法是使用 JPQL。 JPQL 查詢針對實體而不是直接針對數據庫工作,或多或少看起來像 SQL 查詢。我們總是可以編寫一個 JPQL 查詢來計算 JPA 中的行數。
5.1.計算所有行數
entityManager
提供了一個createQuery()
方法,該方法將 JPQL 查詢作為參數並在數據庫上執行該查詢。
public long getAccountsByJPQL() throws ParseException {
Query query = entityManager.createQuery("SELECT COUNT(*) FROM Account a");
return (long) query.getSingleResult();
}
5.2.根據單一條件統計結果行數
在 JPQL 查詢中,我們可以像在原始 SQL 中一樣包含WHERE
條件來過濾查詢併計算返回的行數。
public long getAccountsByPermissionUsingJPQL() throws ParseException {
Query query = entityManager.createQuery("SELECT COUNT(*) FROM Account a WHERE a.permission = ?1");
query.setParameter(1, permissionRepository.findByType("admin"));
return (long) query.getSingleResult();
}
5.3.根據多個條件計算結果行數
在 JPQL 查詢中,我們可以像在原始 SQL 中一樣在WHERE
子句中包含多個條件來過濾查詢併計算返回的行數。
public long getAccountsByPermissionAndCreatedOnUsingJPQL() throws ParseException {
Query query = entityManager.createQuery("SELECT COUNT(*) FROM Account a WHERE a.permission = ?1 and a.createdOn > ?2");
query.setParameter(1, permissionRepository.findByType("admin"));
query.setParameter(2, new Timestamp(getDate().getTime()));
return (long) query.getSingleResult();
}
六,結論
在本教程中,我們學習了一種不同的方法來計算 JPA 中的行數。 CriteriaBuilder
和 Spring Data JPA 查詢派生等規範幫助我們輕鬆編寫不同條件的計數查詢。
雖然CriteriaQuery
和 Spring Data JPA 查詢派生可以幫助我們構建不需要原始 SQL 知識的查詢,但在某些用例中,如果它不能達到目的,我們始終可以使用 JPQL 編寫原始 SQL。
與往常一樣,示例代碼可以在 GitHub 上獲取。