BackEnd/Spring Boot

[Spring JPA] save, saveAll, saveAllAndFlush, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•œ ํšจ์œจ๊ณผ ์„ฑ๋Šฅ ์ฐจ์ด

ddonghyeo 2024. 6. 18. 02:52

JPA์˜ save(), saveAll(), saveAllAndFlush() ๋ฉ”์„œ๋“œ๋“ค์„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๊ฐœ๋…๊ณผ ํ•จ๊ป˜ ํšจ์œจ๊ณผ ์„ฑ๋Šฅ์— ๋Œ€ํ•œ ์ฐจ์ด๋ฅผ ์•Œ์•„๋ณด๊ฒ ๋‹ค.

1. save()

 

๋‹จ๊ฑด ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

 

@Transactional
@Override
public <S extends T> S save(S entity) {

    Assert.notNull(entity, "Entity must not be null");

    if (entityInformation.isNew(entity)) {
        entityManager.persist(entity);
        return entity;
    } else {
        return entityManager.merge(entity);
    }
}

 

 

๋จผ์ € isNew() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์—”ํ‹ฐํ‹ฐ์˜ ๊ธฐ๋ณธ ํ‚ค ๊ฐ’์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ์ธ์ง€ ๊ฒ€์‚ฌํ•œ๋‹ค.

 

public boolean isNew(T entity) {
	//...
    return id ==null;
    
}

 

๊ตฌ์ฒด์ ์œผ๋กœ ์‚ดํŽด๋ณด๋ฉด id๊ฐ€ null์ธ์ง€๋ฅผ ํ†ตํ•ด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

 

id๊ฐ€ null์ด๋ผ๋ฉด em.persist()๋ฅผ,  null์ด ์•„๋‹ˆ๋ผ๋ฉด em.merge()๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

 

์ฆ‰,

 

1. ๋งŒ์•ฝ ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ(New, ๋น„์˜์† ์ƒํƒœ)๋ผ๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅํ•œ๋‹ค. (persist)

 

2. ๊ธฐ์กด์— ์กด์žฌํ•˜๋˜ ์—”ํ‹ฐํ‹ฐ์ผ ๊ฒฝ์šฐ, Detached ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋ฐ˜์˜ํ•œ๋‹ค. (merge)

 

๋ผ์ดํ”„ ์‚ฌ์ดํด์˜ ๊ธฐ๋ณธ์ ์ธ ๋‚ด์šฉ์ด๋‹ค.

Entity Life Cycle

 

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ save()๋ฅผ ํ†ตํ•ด Entity๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋ณด๊ด€ํ•ด๋‘๊ณ , ํŠธ๋žœ์žญ์…˜์ด ๋ชจ๋‘ ์ข…๋ฃŒ๋˜๋ฉด 

 

commit ์ด ํ˜ธ์ถœ ๋  ๋•Œ flush()๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด์„œ DB์— ์ €์žฅ๋œ๋‹ค.

 

 

 

1-1. save() ์˜ ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„?

save() ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ๋Š” ์‹ค์ œ SQL ์ฟผ๋ฆฌ๋ฌธ์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— INSERT ๋ช…๋ น์„ ํ•  ๊ฒƒ์ธ์ง€, UPDATE ๋ช…๋ น์„ ํ•  ๊ฒƒ์ธ์ง€ ๋‚˜๋‰˜๊ฒŒ ๋˜๋Š” ๋ถ„๊ธฐ์ ์ด ์กด์žฌํ•œ๋‹ค.

 

์œ„ ๋‚ด์šฉ๊ณผ ๊ฐ™์ด ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ํ†ตํ•ด ๊ฒฐ์ •ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋ฅผ ์œ„ํ•ด์„œ save() ๋ฉ”์„œ๋“œ์—์„œ๋„ ์กฐํšŒ๊ฐ€ ์ผ์–ด๋‚˜๊ฒŒ ๋œ๋‹ค.

 

๋”ฐ๋ผ์„œ, ํŠธ๋žœ์žญ์…˜์ด ์œ ์ง€๋˜๋Š” ์ƒํƒœ์ผ ๋•Œ ์—”ํ‹ฐํ‹ฐ ์ˆ˜์ • ํ›„ save() ๋ฉ”์„œ๋“œ๋Š” ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์˜ˆ์‹œ 1)

public void createUser(String name) {
	
    User user = User.builder()
    .name(name)
    .build();

    userRepository.save(user); //์กฐํšŒ 1 + ์‚ฝ์ž… 1
}

 

์œ„ ์ฝ”๋“œ์—์„  ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ(New) ์ด๋ฏ€๋กœ,

 

save() ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์ˆœ๊ฐ„ ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ์ธ์ง€ ๊ฒ€์‚ฌ(์กฐํšŒ 1๋ฒˆ)ํ•˜๊ณ , ํŠธ๋žœ์žญ์…˜์ด ๋ชจ๋‘ ๋๋‚˜๋ฉด INSERT ์ฟผ๋ฆฌ๋ฌธ์ด ์‹คํ–‰ ๋  ๊ฒƒ์ด๋‹ค.

 

 

 

 

์˜ˆ์‹œ 2)

@Transactional
public void updateUser(Long id, String name){
    User user = userRepository.findById(id); //์กฐํšŒ 1

    user.setName("ํ™๊ธธ๋™");
 
    userRepository.save(user); //์กฐํšŒ 1 + ์—…๋ฐ์ดํŠธ 1
    
    //ํŠธ๋žœ์žญ์…˜์ด ๋ชจ๋‘ ๋๋‚˜๋ฉด ๋ณ€๊ฒฝ๋œ ํ•„๋“œ๋ฅผ ์ž๋™์œผ๋กœ DB์— commit
}

 

์œ„ user๋Š” ์ด๋ฏธ id๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ์ด๋‹ค.

 

๋งˆ์ง€๋ง‰์— save() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋ถˆํ•„์š”ํ•œ ์กฐํšŒ 1๋ฒˆ์ด ์ผ์–ด๋‚˜๊ณ , UPDATE ์ฟผ๋ฆฌ๋ฌธ์ด ์‹คํ–‰ ๋  ๊ฒƒ์ด๋‹ค.

 

ํŠธ๋žœ์žญ์…˜์ด ๋ชจ๋‘ ์ข…๋ฃŒ๋˜๋ฉด, ๋ณ€๊ฒฝ๋œ ํ•„๋“œ๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜์—ฌ commit ๋˜๋ฏ€๋กœ (์ด๋ฅผ ๋”ํ‹ฐ ์ฒดํ‚น์ด๋ผ๊ณ  ํ•œ๋‹ค.), ๋ถˆํ•„์š”ํ•œ ์กฐํšŒ๋ฅผ ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

 

@Transactional
public void updateUser(Long id, String name){
    User user = userRepository.findById(id); //์กฐํšŒ 1

    user.setName("ํ™๊ธธ๋™");
    
    //ํŠธ๋žœ์žญ์…˜์ด ๋ชจ๋‘ ๋๋‚˜๋ฉด ๋ณ€๊ฒฝ๋œ ํ•„๋“œ๋ฅผ ์ž๋™์œผ๋กœ DB์— commit
}

 

 

 

 

 

2. saveAll()

์—ฌ๋Ÿฌ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ผ๊ด„ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

 

@Transactional
@Override
public <S extends T> List<S> saveAll(Iterable<S> entities) {

    Assert.notNull(entities, "Entities must not be null");

    List<S> result = new ArrayList<>();

    for (S entity : entities) {
        result.add(save(entity));
    }

    return result;
}

 

๋‹จ์ˆœ ๋ฐ˜๋ณต๋ฌธ์„ ์ด์šฉํ•ด save() ๋ฉ”์„œ๋“œ๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์‚ฌ์šฉํ•œ ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.

 

ํ•˜์ง€๋งŒ, ๋ถ„๋ช…ํžˆ ์„œ๋น„์Šค๋‹จ์—์„œ save()๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ saveAll()์„ ํ†ตํ•ด ์ผ๊ด„์ฒ˜๋ฆฌ ํ•˜๋Š” ๊ฒƒ์€ ๋ถ„๋ช…ํžˆ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

 

saveAll()์€ ์œ„์—์„œ ๋ณด๋‹ค์‹œํ”ผ ํ•œ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ์—ฌ์žˆ๋‹ค.

 

 

 

๊ธฐ๋ณธ์ ์œผ๋กœ JpaRepository๋ฅผ ์ƒ์†ํ•œ ํด๋ž˜์Šค๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์‚ฌ์šฉ๋œ๋‹ค. (class com.sun.proxy.$ProxyXXX)

 

save()๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด ํ˜ธ์ถœ๋งŒ ๋งŒํผ ํ•ด๋‹น ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํƒ€๊ฒŒ๋˜๊ณ ,

 

savAll()๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ•œ ๋ฒˆ๋งŒ ํƒ€๊ณ  save()๋ฅผ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ•˜๊ธฐ ๋•Œ๋ฌธ์—

 

์—ฌ๋Ÿฌ๋ฒˆ์˜ save() ํ˜ธ์ถœ๋ณด๋‹ค saveAll() ํ˜ธ์ถœ ํ•œ ๋ฒˆ์ด ๋” ํšจ์œจ์ ์ด๋‹ค.

 

 

3.saveAllAndFlush()

@Transactional
@Override
public <S extends T> List<S> saveAllAndFlush(Iterable<S> entities) {

    List<S> result = saveAll(entities);
    flush();

    return result;
}

 

saveAllAndFlush()๋Š” saveAll()์„ ํ˜ธ์ถœํ•˜๊ณ  ๊ฐ•์ œ๋กœ flushํ•œ๋‹ค.

 

์˜์†์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ ํ›„ ๋‹ค์Œ ๋กœ์ง์—์„œ ์˜์†ํ™” ๋œ ์ƒํƒœ๋ฅผ DB์—์„œ ํ™•์ธํ•ด์•ผ ํ•˜๊ฑฐ๋‚˜, ํ…Œ์ŠคํŠธ & ๋””๋ฒ„๊น… ์šฉ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ

 

๋”ํ‹ฐ ์ฒดํ‚น์— ํ•„์š”ํ•œ ์—ฐ์‚ฐ์ด ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐœ์ƒ๋˜๊ณ , DB ์ปค๋ฐ‹ ์ „์ด๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

 

 

 

์ฐธ๊ณ 
https://docs.spring.io/spring-data/jpa/reference/repositories/core-concepts.html
https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https://blog.kakaocdn.net/dn/b6Csm8/btrR8yFlZvk/9JK0yUkShKwgIBTFTwAvak/img.png
https://pingpongdev.tistory.com/25