본문 바로가기

Java/JPA

[JPA] Querydsl 벌크삭제

 

Querydsl 을 사용해서 벌크삭제를 해봤다.

 

아래와 같은 세개의 엔티티 클래스가 있다면, 

' User ' , ' Order ', ' Post '

=> 각 User는 여러 Order를 가질 수 있고, 또한 여러 Post를 가질 수 있음.

 

User 엔티티 삭제로직을 처음에는 아래처럼 만들었다.

(User의 pk가 'userId'와 'userCode'라고 가정. 세세한 로직은 생략.)

if (!deleteList.isEmpty()) {
    List<User> delList = new ArrayList<>();
    for (Map<String, Object> del : deleteList) {
        String userId =  String.valueOf(del.get("userId"));
        String userCode =  String.valueOf(del.get("userCode"));

        // 생략

        User user = new User();
        user.setUserId(userId);
        user.setUserCode(userCode);
        delList.add(user);
    }
    userRepository.deleteAll(delList);
}

=> 만일 삭제할 리스트(deleteList)가 있다면

for문으로 llist의 각각의 요소에 대한 entity를 생성 & deList에 담기 =>  deleteAll 메소드 실행.

* deleteAll 은 삭제할 엔티티의 수만큼 delete 쿼리를 실행.


문제점은  ' Order ', ' Post ' 에서 해당하는 엔티티들의 삭제였다.

각각 oneToMany 관계이기 때문에

삭제하는 user의 정보가 하나여도 order는 수십개가 될 수 있고,

user의 정보가 여러개라면 order의 갯수는그만큼 더 많아진다. (post도 마찬가지)


전부 for문을 돌리기엔 비효율적인 것 같아서 querydsl을 사용해봄.

import com.querydsl.jpa.impl.JPAQueryFactory;

 

(delUserList는 삭제할 userId들의 List라고 가정. 세세한 로직은 생략.)

// param => String userCode, List<Map<String, Object>> deleteList, List<String> delIdList

if(!deleteList.isEmpty() && !delIdList.isEmpty()){
  
        // 생략

    JPAQueryFactory queryFactory = new JPAQueryFactory(em);

    QUser user = QUser.user;
    long delUserCount = queryFactory.delete(user)
            .where(user.userCode.eq(userCode)
                    .and(user.userId.in(delIdList)))
            .execute();


    if(delUserCount == delIdList.size()){

        QOrder order = QOrder.order;
        queryFactory.delete(order)
                .where(order.userCode.eq(userCode)
                        .and(order.userId.in(delIdList)))
                .execute();

        QPost post = QPost.post;
        queryFactory.delete(post)
                .where(post.userCode.eq(userCode)
                        .and(post.userId.in(delIdList)))
                .execute();
    
    } else {
        throw new RuntimeException("err");
    }
}

쿼리로 조건에 해당하는 entity들을 한꺼번에 삭제!!

 

=> querydsl은 삭제완료된 row의 갯수를 반환!! (Long타입)

@Transactional로 관리하고 있지만 'delUserCount' 로 한번더 체크해줬다.

 

.execute() 메소드 :  이 메소드를 호출할 때 쿼리가 삭제됨.

 

이 방식이 맞는지는 모르겠다. 더 좋은 방법을 찾으면 계속해서 수정해나갈 예정.