写点什么

Spring Data Jpa deleteAll 大概了解

用户头像
ilovealt
关注
发布于: 2020 年 11 月 07 日

模块命名就用User吧 使用springboot 2.2.6 + JPA

问题起因

使用springboot开发的模块,部署上去过一段时间都OOM;翻了几遍同事写的代码感觉没啥问题,就是一个定时器1小时

清空一次User表,然后重新再去其他地方拉取下一批数据(前提是我知道这批数据量很小);

定时器是后加的,数据库表中已经有100万条数据量啦,结果就是这个deleteAll方法,把数据全读出来,OOM。

使用

//调用删除全部数据的方法,跟进入deleteAll方法,会进入到一个CrudRepository接口
repository.deleteAll();
//自己定义业务代码
@Repository
public interface UserRepository extends JpaRepository<User,Integer> {}
//***下面接口关系不是全部,下面接口关系不是全部,下面接口关系不是全部***
//只是挑选了与此问题相关的复制下来
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {}
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {}
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {}
//默认实现类,我们能够直接使用上面的deleteAll方法,也是它的原因
@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID> {}
//和我们调用的deleteAll方法完全对应的方法在这个类中只有一个
@Transactional
public void deleteAll() {
for (T element : findAll()) {
delete(element);
}
}

终于找到你“findAll()”,人家是先把数据都查出来,然后一个一个删除,WCL!!!;

替代方法

找一个替代方法,直接执行SQL语句的方法“DELETE FROM user”;这里为了还原问题(在一个事务中,先删除在添加),一个语句执行删除sql,一个用add添加数据。

//提前注入javax.persistence.EntityManager中的EntityManager接口;
private final EntityManager entityManager;
//方法会失败,错误提示为
//javax.persistence.TransactionRequiredException: Executing an update/delete query
//executeUpdate方法对于update操作会检查是否有事务存在,结果没找到报此错误,可以代码一下。
//没有做事务,那就搞一个事务处理上去
public void getTest(){
Query query = entityManager.createNativeQuery("DELETE FROM user WHERE 1=1");
query.executeUpdate();
add();
}
//方法还是会失败,错误提示为
//java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager -
//use Spring transactions or EJB CMT instead
//共享EntityManager不允许创建事务(个人理解:getTransaction()创建新对象的方法,导致entityManager实现类
//的内部属性状态不一致,存在安全问题。理解不深甚至是错误,希望您不吝赐教!)
public void getTest(){
entityManager.getTransaction().begin();
Query query = entityManager.createNativeQuery("DELETE FROM user WHERE 1=1");
query.executeUpdate();
add();
entityManager.getTransaction().commit();
}
//正确做法是entityManager执行语句,把事务处理交给spring框架
@Transactional(rollbackFor = Exception.class)
public void getTest(){
Query query = entityManager.createNativeQuery("DELETE FROM user WHERE 1=1");
query.executeUpdate();
add();
}
//当然上面有一个手动创建事务的方法,没有成功,我们在这里以其他方式再试试
//这个方法可以,就是在方法中创建一个新的EntityManager进行操作
public void getTestFa(){
EntityManager em = entityManager.getEntityManagerFactory().createEntityManager();
em.getTransaction().begin();
Query query = em.createNativeQuery("DELETE FROM user WHERE 1=1");
query.executeUpdate();
add();
em.getTransaction().commit();
em.close();
}
//工厂方法也可以注入,直接使用entityManagerFactory.createEntityManager();
private final EntityManagerFactory entityManagerFactory;

总结: 直接执行delete方法,都需要事务管理,一种是用spring的事务注解,

另一种是创建新的EntityManager手动事务管理;



成长快乐!成长快乐!成长快乐!



发布于: 2020 年 11 月 07 日阅读数: 31
用户头像

ilovealt

关注

不忘初心,方得始终! 2018.05.02 加入

When you feel like giving up,remember why you held on so long in the first place.

评论

发布
暂无评论
Spring Data Jpa deleteAll大概了解