Spring JPA学习之delete方法示例详解
作者:烟雨戏江南 发布时间:2021-11-23 12:22:55
一、deleteById 和 delete
为什么要把这两个方法放在一起呢?我们先看源码再说
deleteById(Id id)(通过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)));
}
delete(T entity)(通过实体对象进行删除)
@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 求出 entity 对象,然后调用了 delete 的方法。也就是说,这两个方法同根同源,使用起来差距不大,结果呢?也是一样的,就是单条删除。实际使用中呢,也是使用 deleteById 的情况比较多,废话少说,try it。
实例
service 层
添加deleteById方法(deleteById 是 JPA 自带接口不需要在dao层中添加)
@Transactional
public void deleteById(Integer id){
userDao.deleteById(id);
}
control层
/**
* 通过id进行删除数据
* @param id
*/
@GetMapping("/deleteById")
public void deleteById(Integer id){
userService.deleteById(id);
}
执行请求 /deleteById?id=2
,控制台打印如下:
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 和 deleteAll
1、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);
}
}
结论
通过源码可以看出,就是遍历 ids 然后循环调用上面的 deleteById(Id id) 方法。
2、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);
}
}
结论
这个呢?也就是遍历 entities 然后循环调用上面的 delete(T entity) 方法
还有一个不传参数的deleteAll()方法来删除所有数据(慎用)
@Override
@Transactional
public void deleteAll() {
for (T element : findAll()) {
delete(element);
}
}
就是通过findAll求出所有实体对象然后循环调用delete方法
综上所述,我们发现以上所有的删除事件都是调用了delete(T entity)方法,也就是差距不是很大,就是单条 和多条删除的区别。
实例
service 层
添加 deleteAllById 方法(deleteAllById 是三方件自带接口不需要在dao层中添加)
@Transactional
public void deleteAllById(Iterable ids){
userDao.deleteAllById(ids);
}
control层
/**
* 通过id进行批量删除
* @param ids
*/
@GetMapping("/deleteAllById")
public void deleteAllById(Integer[] ids){
userService.deleteAllById(Arrays.asList(ids));
}
浏览器测试成功 /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=?
由此可以看出,数据是一条一条的进行了删除。
三、deleteAllInBatch 和 deleteAllByIdInBatch
1、deleteAllInBatch(Iterable<T> 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(Iterable<T> entities)的实现原理: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=?
2、deleteAllByIdInBatch(Iterable<ID> ids)源码(通过ids批量删除)
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
结论:
从上面两种删除接口来看,第二种实现比起第一种更加的快捷;
第一种就是一条一条的进行删除操作,如果有万级的数据,执行起来肯定非常耗时,所以如果数据量比较大的话,还是建议大家使用第二种。
来源:https://juejin.cn/post/7221425806349729848
猜你喜欢
- Java集合是java提供的工具包,包含了常用的数据结构:集合、链表、队列、栈、数组、映射等。Java集合工具包位置是java.util.*
- 前提:windows上安装jdk1.启动jar脚本@echo offSTART "app" javaw -jar app
- 0.前言HashMap简述:HashMap 基于哈希表的 Map 接口实现,是以 key-value 存储形式存在,即主要用来存放键值对。H
- 通用配置#下面介绍的整合JDBC和整合MyBatis都需要添加的实体类和配置数据库表#CREATE TABLE `user` ( `id`
- 本文实例讲述了C++语言实现线性表之链表实现方法。分享给大家供大家参考。具体分析如下:插入、删除结点的代码有点多,但这样提高了代码的可读性,
- 今天在接手别人的一个项目的时候遇到一个坑,坑死我了;是一个打包的问题,好不容易我把代码写完了准备打包测试了,结果java -jar xxx.
- 因为涉及到 io 流输入问题,如果不关闭会一直占用资源。所以使用过后要及时关闭,防止资源一直被占用。Scanner在使用前要导入 java.
- java 数据结构单链表的实现 单链表实现链表的打印及元素删除操作,链表的实现主要是next属性的定义,将一堆节点关
- mybatis update并非所有字段需要更新mybatis update需求:更新字段作为参数,未更新字段不传入解决办法<upda
- 在讲述这个模式之前,我们先看一个案例:游戏回档游戏的某个场景,一游戏角色有生命力、攻击力、防御力等数据,在打Boss前和后会不一样,我们允许
- 目录写在前面引入guava依赖包怎么做变量转换写在前面有时候需要处理对象属性的getter、setter方法,或者将属性与数据表字段进行相互
- 实现效果:列出某个目录下的特定后缀名文件(如,列出D盘根目录下txt后缀的文件)import java.io.File;import jav
- 1 pom.xml文件注:热部署功能spring-boot-1.3开始有的<!--添加依赖--><dependency&g
- Android权限一般是在AndroidManifest.xml中声明,在安装或首次使用的时候系统会自动提示用户是否提供权限Android官
- synchronized关键字synchronized,我们谓之锁,主要用来给方法、代码块加锁。当某个方法或者代码块使用synchroniz
- 修改加密和验证方法/** * 生成BCryptPasswordEncoder密码 *
- 一.HashMap 和Hashtable 的区别我们先看2个类的定义 public class Hashtable exten
- 前言java 10 引进一种新的闪闪发光的特性叫做局部变量类型推断。听起来很高大上吧?它是什么呢? 下面的两个情景是我们作为 Java 开发
- 一:需求当小数位很多的时候,小数位后面可能有一些多余的0并没有任何实际意义。所以在某些业务需求下可以去掉这些多余的0。例如:0.2000可以
- 最近做一个需求,需求中的bean只用于生成一次json使用,所以想通过配置来动态的生成,查了一下,java还真有这个实现。java动态的生成