1. deleteById(ID id) および delete(T エンティティ)
なぜこれら 2 つの方法を組み合わせるのですか? まずはソースコードを見てみましょう
deleteById ソース コード (ID による削除)
@Transactional
@Override
public void deleteById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
delete(findById(id).orElseThrow(() -> new EmptyResultDataAccessException(
String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1)));
}
复制代码
ソース コードの削除 (エンティティ オブジェクトを介して削除)
@Override
@Transactional
@SuppressWarnings("unchecked")
public void delete(T entity) {
Assert.notNull(entity, "Entity must not be null!");
if (entityInformation.isNew(entity)) {
return;
}
Class<?> type = ProxyUtils.getUserClass(entity);
T existing = (T) em.find(type, entityInformation.getId(entity));
// if the entity to be deleted doesn't exist, delete is a NOOP
if (existing == null) {
return;
}
em.remove(em.contains(entity) ? entity : em.merge(entity));
}
复制代码
一目瞭然!deleteById は、まずメソッド本体の id からエンティティ オブジェクトを見つけてから、delete メソッドを呼び出します。つまり、この 2 つの方法は根本と起源が同じであり、使用方法に大きな違いはありません。同じことが当てはまります。つまり、単一の削除です。実際の使用では、deleteById がよく使用されるので、ナンセンスな話はやめて試してみてください。
サービス層に deleteById メソッドを追加します (deleteById はサードパーティ ソフトウェアに付属するインターフェイスであり、 dao 層に追加する必要はありません)。
@Transactional
public void deleteById(Integer id){
userDao.deleteById(id);
}
复制代码
制御層
/**
* 通过id进行删除数据
* @param id
*/
@GetMapping("/deleteById")
public void deleteById(Integer id){
userService.deleteById(id);
}
复制代码
ブラウザテスト成功http://localhost:7777/deleteById?id=2
コンソールには、次のように 2 行の sql が出力されます。
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: delete from user where id=?
复制代码
最初に select によってエンティティ オブジェクトが存在するかどうかを確認し、次に id によって削除することがわかります。
二、deleteAllById(Iterable<? extends ID> ids) と deleteAll(Iterable<? extends T> entities)
deleteAllById(Iterable<? extends ID> ids) (IDによる一括削除)
@Override
@Transactional
public void deleteAllById(Iterable<? extends ID> ids) {
Assert.notNull(ids, "Ids must not be null!");
for (ID id : ids) {
deleteById(id);
}
}
复制代码
ソース コードからわかるように、ID をトラバースしてから、上記の deleteById(Id id) メソッドをループで呼び出します。
deleteAll(Iterable<? extends T> entities) (エンティティ オブジェクトによる一括削除)
@Override
@Transactional
public void deleteAll(Iterable<? extends T> entities) {
Assert.notNull(entities, "Entities must not be null!");
for (T entity : entities) {
delete(entity);
}
}
复制代码
これはどうですか?つまり、エンティティをトラバースし、上記の delete(T entity) メソッドをループで呼び出します。
すべてのデータを削除するためのパラメーターを渡さない deleteAll() メソッドもあります (注意して使用してください)。
@Override
@Transactional
public void deleteAll() {
for (T element : findAll()) {
delete(element);
}
}
复制代码
findAll を介してすべてのエンティティ オブジェクトを検索し、ループ内で delete メソッドを呼び出すことです。
要約すると、上記のすべての削除イベントが delete(T entity) メソッドを呼び出していることがわかりました。つまり、違いはそれほど大きくありません。つまり、単一の削除と複数の削除の違いです。
複数の削除のシナリオをテストしてみましょう:
サービス レイヤーに deleteAllById メソッドを追加します (deleteAllById はサードパーティ ソフトウェアに付属するインターフェイスであり、 dao レイヤーに追加する必要はありません)。
@Transactional
public void deleteAllById(Iterable ids){
userDao.deleteAllById(ids);
}
复制代码
制御層
/**
* 通过id进行批量删除
* @param ids
*/
@GetMapping("/deleteAllById")
public void deleteAllById(Integer[] ids){
userService.deleteAllById(Arrays.asList(ids));
}
复制代码
ブラウザのテストは成功しましたhttp://localhost:7777/deleteAllById?id=3,4
削除:
削除後:
コンソールには次のように表示されます。
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: delete from user where id=?
Hibernate: delete from user where id=?
复制代码
このことから、データが 1 つずつ削除されていることがわかります。
三、deleteAllInBatch(Iterable entities) と deleteAllByIdInBatch(Iterable ids)
deleteAllInBatch(Iterable entities) ソース コード (エンティティ オブジェクトによる一括削除)
public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
@Override
@Transactional
public void deleteAllInBatch(Iterable<T> entities) {
Assert.notNull(entities, "Entities must not be null!");
if (!entities.iterator().hasNext()) {
return;
}
applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), entities, em)
.executeUpdate();
}
复制代码
/**
* Creates a where-clause referencing the given entities and appends it to the given query string. Binds the given
* entities to the query.
*
* @param <T> type of the entities.
* @param queryString must not be {@literal null}.
* @param entities must not be {@literal null}.
* @param entityManager must not be {@literal null}.
* @return Guaranteed to be not {@literal null}.
*/
public static <T> Query applyAndBind(String queryString, Iterable<T> entities, EntityManager entityManager) {
Assert.notNull(queryString, "Querystring must not be null!");
Assert.notNull(entities, "Iterable of entities must not be null!");
Assert.notNull(entityManager, "EntityManager must not be null!");
Iterator<T> iterator = entities.iterator();
if (!iterator.hasNext()) {
return entityManager.createQuery(queryString);
}
String alias = detectAlias(queryString);
StringBuilder builder = new StringBuilder(queryString);
builder.append(" where");
int i = 0;
while (iterator.hasNext()) {
iterator.next();
builder.append(String.format(" %s = ?%d", alias, ++i));
if (iterator.hasNext()) {
builder.append(" or");
}
}
Query query = entityManager.createQuery(builder.toString());
iterator = entities.iterator();
i = 0;
while (iterator.hasNext()) {
query.setParameter(++i, iterator.next());
}
return query;
}
复制代码
上記のソース コードから、deleteAllInBatch (反復可能なエンティティ) の実装原理を大まかに推測できます。delete from %s where x=? or x=?
実際にテストします。http://localhost:7777/deleteAllInBatch?ids=14,15,16&names=a,b,c&ages=0,0,0
コンソールには次のように表示されます。
Hibernate: delete from user where id=? or id=? or id=?
复制代码
deleteAllByIdInBatch(Iterable ids) ソース コード (id ごとに一括削除)
public static final String DELETE_ALL_QUERY_BY_ID_STRING = "delete from %s x where %s in :ids";
@Override
@Transactional
public void deleteAllByIdInBatch(Iterable<ID> ids) {
Assert.notNull(ids, "Ids must not be null!");
if (!ids.iterator().hasNext()) {
return;
}
if (entityInformation.hasCompositeId()) {
List<T> entities = new ArrayList<>();
// generate entity (proxies) without accessing the database.
ids.forEach(id -> entities.add(getReferenceById(id)));
deleteAllInBatch(entities);
} else {
String queryString = String.format(DELETE_ALL_QUERY_BY_ID_STRING, entityInformation.getEntityName(),
entityInformation.getIdAttribute().getName());
Query query = em.createQuery(queryString);
/**
* Some JPA providers require {@code ids} to be a {@link Collection} so we must convert if it's not already.
*/
if (Collection.class.isInstance(ids)) {
query.setParameter("ids", ids);
} else {
Collection<ID> idsCollection = StreamSupport.stream(ids.spliterator(), false)
.collect(Collectors.toCollection(ArrayList::new));
query.setParameter("ids", idsCollection);
}
query.executeUpdate();
}
}
复制代码
上記のソース コードから、deleteAllByIdInBatch (Iterable ids) の実装原理を大まかに推測できます。delete from %s where id in (?,?,?)
実際にテストします。http://localhost:7777/deleteAllByIdInBatch?ids=17,18,19
コンソールには次のように出力されます。
Hibernate: delete from user where id in (? , ? , ?)
复制代码
パラメータなしの deleteAllInBatch() メソッドもあります。ソース コードは次のとおりです。
@Override
@Transactional
public void deleteAllInBatch() {
em.createQuery(getDeleteAllQueryString()).executeUpdate();
}
public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
private String getDeleteAllQueryString() {
return getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName());
}
复制代码
ソース コードから実装原理を推測することは難しくありません。テストのコンソール データを直接提供することは言うまでもありません。Hibernate: delete from user
最終的な結論:
上記の 2 つの削除インターフェイスから、2 番目の実装は最初の実装よりも高速です.1 番目の実装は 1 つずつ削除することです.数万のデータがある場合、実行に非常に時間がかかる必要があるため、データが量が比較的多い場合は、2本目をお使いいただくことをお勧めします。