Programming/Spring

JPA / Persistence Context / Transactional

osean 2023. 1. 14. 01:44

Goal

  • JDBC
  • Spring Data JPA
  • Persistence Context

JDBC?

Spring JDBC ๋ž€ Spring Framework ์™€ DB ๊ฐ„ ํ†ต์‹ ์„ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฒค๋”์‚ฌ์˜ ์ œํ’ˆ์— ๊ด€๊ณ„์—†์ด DB ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ค€๋‹ค. ํ•˜์ง€๋งŒ JDBC ๋Š” Persistence Layer ์™€ ๊ธด๋ฐ€ํ•œ ๊ด€๊ณ„๋ฅผ ๋งบ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ Connection ์„ค์ •ํ•˜๊ฑฐ๋‚˜ Statement ๋ฅผ ์ด์šฉํ•ด ์›ํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ ํ›„ Statement ๋ฅผ ์ง์ ‘ ๋‹ซ์•„์ค˜์•ผ ํ•˜๋Š” ๋“ฑ์˜ ๋ฌธ์ œ์ ์ด ์•ผ๊ธฐ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ค‘๋ณต ์ฝ”๋“œ์˜ ์žฌ์ƒ์‚ฐ์œผ๋กœ ์ธํ•ด ์œ ์ง€๋ณด์ˆ˜์˜ ๋‚œ์ด๋„๊ฐ€ ์ƒ์Šนํ•˜๊ฒŒ ๋œ๋‹ค.

 

JDBC Architecture (์ถœ์ฒ˜ : Microsoft Tech Community)


Spring Data JPA

ORM(Object Relation Mapper) ์ค‘ ํ•˜๋‚˜๋กœ, ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ Java ์˜ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์ง•๊ฒ€๋‹ค๋ฆฌ ์—ญํ• ์„ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. JPA ์™€ ๊ฐ™์€ ORM ์€ IoC(์ œ์–ด์˜ ์—ญ์ „) ์„ ํ†ตํ•ด JDBC ์—์„œ ๋ฐœ์ƒํ•˜๋Š” Connection ์ด๋‚˜ Statement ๊ด€๋ฆฌ ๋“ฑ์˜ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ Query ์ž‘์„ฑ์„ ์ค„์ด๊ณ  ์˜ค๋กฏ์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.
์ด๋Ÿฌํ•œ JPA ๋Š” Hibernate ๋ผ๋Š” ๊ตฌํ˜„์ฒด๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence Context)์— ์†ํ•œ Entity ๋ฅผ ์†์‰ฝ๊ฒŒ ๊ด€๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Repository / Method Define

@Repository
interface ProductOptionRepository :
    JpaRepository<ProductOption, String>,
    QuerydslPredicateExecutor<ProductOption> {

    fun findProductOptionsByProductIdIn(productIds: List<String>): List<ProductOption>
}

JPA ์— ์˜ํ•ด ๋งŒ๋“ค์–ด์ง„ Query

select p1_0.id,
       p1_0.app_price,
       p1_0.name,
       p1_0.product_id,
       p1_0.registration_date,
       p1_0.search_keyword,
       p1_0.shelf_life,
       p1_0.status,
       p1_0.web_price
from product_option p1_0
where p1_0.product_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

EntityManager / EntityManagerFactory

JPA ์˜ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด EntityManager ์— ์˜ํ•ด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , Entity ๋กœ ๋“ฑ๋ก๋œ ๊ฐ์ฒด๋“ค์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์˜ํ•ด ์ƒ๋ช…์ฃผ๊ธฐ๊ฐ€ ๊ด€๋ฆฌ๋˜๋ฉฐ, EntityManager ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์˜ํ•ด ๊ด€๋ฆฌ๋œ๋‹ค.
์ด ๋•Œ EntityManagerFactory ๋ฅผ ํ†ตํ•ด EntityManager ๊ฐ€ ์ƒ์„ฑ๋˜๋Š”๋ฐ, EntityManagerFactory ๋Š” Thread-safe, EntityManager ๋Š” Thread-safe ํ•˜์ง€ ๋ชปํ•˜๋‹ค. ๋•Œ๋ฌธ์— EntityManager ๋Š” ์Šค๋ ˆ๋“œ ๋‹น ํ•˜๋‚˜๋งŒ ์กด์žฌํ•˜๊ฒŒ ๋œ๋‹ค.
๋˜ํ•œ EntityManager ๋Š” Transaction ์ˆ˜ํ–‰ ์‹œ, ๋‚ด๋ถ€์ ์œผ๋กœ Connection Pool ์—์„œ ํ•˜๋‚˜์˜ Connection ์„ ์ด์šฉํ•˜๊ณ  Transaction ์ด ์ข…๋ฃŒ๋˜๋ฉด Connection ์„ ๋‹ค์‹œ Connection Pool ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๐Ÿ” EntityManagerFactory ๋Š” ์™œ ์ƒ์„ฑ ๋น„์šฉ์ด ๋น„์Œ€๊นŒ?
> ์ถ”์ธกํ•˜๊ฑด๋ฐ ์•„๋งˆ JDBC ์™€ ๋น„์Šทํ•˜๊ฒŒ DB ์™€ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ณผ์ •์— ๋งŽ์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ธ๊ฑธ๊นŒ? ์Šคํ„ฐ๋”” ๋•Œ ์งˆ๋ฌธ ํ•ด์•ผ๊ฒ ๋‹ค.
// ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ, EntityFactoryManager ์ดˆ๊ธฐํ™”
public abstract class AbstractEntityManagerFactoryBean implements
		FactoryBean<EntityManagerFactory>, BeanClassLoaderAware, BeanFactoryAware, BeanNameAware,
		InitializingBean, DisposableBean, EntityManagerFactoryInfo, PersistenceExceptionTranslator, Serializable {
        	private EntityManagerFactory buildNativeEntityManagerFactory() {
                EntityManagerFactory emf;
                try {
                    emf = createNativeEntityManagerFactory();
                }
                catch (PersistenceException ex) {
                    if (ex.getClass() == PersistenceException.class) {
                        // Plain PersistenceException wrapper for underlying exception?
                        // Make sure the nested exception message is properly exposed,
                        // along the lines of Spring's NestedRuntimeException.getMessage()
                        Throwable cause = ex.getCause();
                        if (cause != null) {
                            String message = ex.getMessage();
                            String causeString = cause.toString();
                            if (!message.endsWith(causeString)) {
                                ex = new PersistenceException(message + "; nested exception is " + causeString, cause);
                            }
                        }
                    }
                    if (logger.isErrorEnabled()) {
                        logger.error("Failed to initialize JPA EntityManagerFactory: " + ex.getMessage());
                    }
                    throw ex;
                }

                JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
                if (jpaVendorAdapter != null) {
                    jpaVendorAdapter.postProcessEntityManagerFactory(emf);
                }

                if (logger.isInfoEnabled()) {
                    logger.info("Initialized JPA EntityManagerFactory for persistence unit '" + getPersistenceUnitName() + "'");
                }
                return emf;
            }
        }

Persistence Context

EntityManager ๋Š” Transaction ์ž‘์—… ์ˆ˜ํ–‰ ์‹œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— Entity ๋ฅผ ๋‹ด๊ณ , ํ•ด๋‹น Entity ์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence Context) ๋Š” ๋ฌด์—‡์„ ์˜๋ฏธํ• ๊นŒ?

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ž€ '์˜๊ตฌ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ํ™˜๊ฒฝ' ์ด๋ผ๋Š” ๋œป์œผ๋กœ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ DB ์‚ฌ์ด์˜ 1์ฐจ ์บ์‹œ ๊ฐ™์€ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„๋‹ค.
๋‹จ์ˆœํžˆ ์บ์‹œ์™€ ๊ฐ™์ด ์ž‘๋™์œผ๋กœ ๋๋‚˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก๋œ Entity ์ธ์Šคํ„ด์Šค๋Š” ๋ณ€๊ฒฝ ๊ฐ์ง€, ๋™์ผ์„ฑ ๋ณด์žฅ, ์“ฐ๊ธฐ ์ง€์—ฐ ๋“ฑ ์—ฌ๋Ÿฌ ํŽธ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ๋˜ํ•œ, ํ•ด๋‹น Transaction ์—์„œ ์ˆ˜ํ–‰๋˜์–ด์•ผ ํ•  ๋ชจ๋“  Query ๊ฐ€ commit ๋œ ๋’ค์— Entity ์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค. (RDBMS ์˜ Rollback ๊ณผ ๋น„์Šทํ•˜๋‹ค.)
ํ•˜์ง€๋งŒ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ํฌํ•จ๋˜์ง€ ์•Š๋Š” ์—”ํ‹ฐํ‹ฐ๋Š” (Transaction ์ „ํŒŒ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๊ฒฝ์šฐ) ์กฐํšŒ ์‹œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. 

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—  ๊ด€๋ฆฌ๋˜๋Š” Entity Instance

@Service
class ProductService(
    private val productOptionRepository: ProductOptionRepository
) {
    @Transactional
    fun updateProductOption(product: Product, productOption: ProductOption) {
        val productOption = productOptionRepository.findById("10")
            .orElseThrow { IllegalArgumentException("์ œํ’ˆ ์˜ต์…˜์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") }

        val product = productOption.product

		// EntityManager ์— ์˜ํ•ด Dirty Checking
        // ๋ณ€๊ฒฝ์ด ํ™•์ธ๋˜๋ฉด ๋ณ€๊ฒฝ ๋‚ด์šฉ์ด DB ์— ๋ฐ˜์˜๋œ๋‹ค.
        productOption.name = "256GB"
        product?.name = "[์‹ ์ œํ’ˆ] ์•„์ดํฐ15"
    }
}

Transaction ์ „ํŒŒ ๋ฒ”์œ„๋ฅผ ๋„˜์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ

@Service
class ProductService(
    private val productOptionRepository: ProductOptionRepository
) {
	@Transactional
	fun mapToDto(productOption: ProductOption): ProductRespDto {
        val productOption = productOptionRepository.findById("10")
            .orElseThrow { IllegalArgumentException("์ œํ’ˆ ์˜ต์…˜์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") }
        
        return ProductRespDto(productOption)
    }
}

class ProductRespDto(
	productOption: ProductOption
) {
	// Transaction ์˜ ์ „ํŒŒ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด Join ํ•˜๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ
	val productName: String = productOption.product.name
    val productOptionName: String = productOption.name
}

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ์ด์ 

  • 1์ฐจ ์บ์‹œ
    • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ๋Š” Entity ์ธ์Šคํ„ด์Šค๋ฅผ ํ˜„์žฌ Transaction ์—์„œ ๋‹ค์‹œ ์กฐํšŒํ•  ๋•Œ, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋ฅผ ์กฐํšŒํ•˜๋„๋ก ํ•œ๋‹ค. ๋งŒ์•ฝ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ฐพ๊ณ ์ž ํ•˜๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด DB ๋ฅผ ํ†ตํ•ด ์กฐํšŒํ•˜์—ฌ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜๊ณ , ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
  • ๋™์ผ์„ฑ ๋ณด์žฅ
val person1 = em.find(Person::class.java, 1L)
val person2 = em.find(Person::class.java, 1L)

// ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” Entity ์ธ์Šคํ„ด์Šค๋Š” ๋™์ผํ•œ ํŠธ๋žœ์ น์…˜ ๋‚ด์—์„œ ์กฐํšŒ ํ•  ๊ฒฝ์šฐ ๊ฐ์ฒด์˜ ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.
println(person1 == person2)
  • ์“ฐ๊ธฐ ์ง€์—ฐ
    • EntityManager ๋Š” ํŠธ๋žœ์žญ์…˜์„ Commit ํ•˜๊ธฐ ์ „์— ๋‚ด๋ถ€์˜ ์ฟผ๋ฆฌ ์ €์žฅ์†Œ์— ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜์—์„œ ํ˜ธ์ถœ๋œ Insert Query ๋ฅผ ๋ชจ์•„๋‘๊ณ , Commit ์ด ๋˜๋Š” ์‹œ์ ์— ์ €์žฅ์†Œ์— ์ €์žฅํ•œ Insert Query ๋ฅผ DB ๋กœ ์ „์†กํ•˜๋Š”๋ฐ ์ด๋ฅผ ์“ฐ๊ธฐ ์ง€์—ฐ์ด๋ผ๊ณ  ํ•œ๋‹ค.
  • ๋ณ€๊ฒฝ ๊ฐ์ง€(Dirty Check)
    • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ๋˜๋Š” Entity ์ธ์Šคํ„ด์Šค๋“ค์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•˜๊ณ , ๋ณ„๋„๋กœ Update Query ๋ฅผ ๋‚ ๋ฆฌ์ง€ ์•Š์•„๋„ DB ๋กœ ์ „์†ก๋œ๋‹ค.
      • flush() ๋ฐœ์ƒ
      • 1์ฐจ ์บ์‹œ ๋ฐ์ดํ„ฐ์™€ Entity ์˜ ์Šค๋ƒ…์ƒท์„ ๋น„๊ต
      • Update Query ์ƒ์„ฑ
      • flush(), ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ๊ฐ’์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ์ „์†ก
      • commit()

 


Entity Lifecycle

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” Entity ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜์†์„ฑ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋œ๋‹ค.

- ๋น„์˜์† ๊ฐ์ฒด(new / transient) : ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์ƒํƒœ
- ์˜์† ๊ฐ์ฒด(managed) : ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” Entity ์ธ์Šคํ„ด์Šค๋กœ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋Š” Dirty Check ์— ์˜ํ•ด ์ž๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ „ํŒŒ๋œ๋‹ค.
- ์ค€์˜์† ๊ฐ์ฒด(detached) : ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ๋˜๋‹ค๊ฐ€ ๋ถ„๋ฆฌ๋œ ์ธ์Šคํ„ด์Šค๋กœ ๋”์ด์ƒ ์ถ”์ ๋˜์ง€ ์•Š๋Š”๋‹ค.
- ์‚ญ์ œ ๊ฐ์ฒด(removed) : ์„ธ์…˜์— ์˜ํ•ด delete() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์‚ญ์ œ๋œ ์ธ์Šคํ„ด์Šค๋กœ ์ธ์ง€ํ•œ๋‹ค. ํ•˜์ง€๋งŒ Entity ์ธ์Šคํ„ด์Šค๋Š” EntityManager ์˜ ์ž‘์—… ๋‹จ์œ„๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์˜์†์„ ์ปจํ…์ŠคํŠธ์— ์กด์žฌํ•œ๋‹ค.

Transaction

Transaction ์ด๋ž€ ํ•˜๋‚˜์˜ ์ž‘์—… ๋‹จ์œ„๋ผ๋Š” ์˜๋ฏธ๋กœ ์—ฌ๋Ÿฌ Query ๋ฅผ ํ•˜๋‚˜์˜ Transaction ์œผ๋กœ ๋ฌถ์–ด Commit ํ•˜๋ฉด DB ์— ๋ฐ˜์˜๋œ๋‹ค. ๋งŒ์•ฝ Transaction ์ˆ˜ํ–‰ ๋„์ค‘ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด Rollback ํ•˜์—ฌ ๋ฐ์ดํ„ฐ์˜ ์›์ž์„ฑ์„ ์œ ์ง€ํ•˜๋„๋ก ํ•œ๋‹ค.
์ด๋Ÿฌํ•œ Transaction ์˜ ํŠน์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

- ์›์ž์„ฑ : Transaction ๋‚ด์˜ ์งˆ์˜๋Š” ๋ชจ๋‘ ์„ฑ๊ณตํ•˜๊ฑฐ๋‚˜ ๋ชจ๋‘ ์‹คํŒจํ•ด์•ผ ํ•œ๋‹ค.
- ์ผ๊ด€์„ฑ : ์ž‘์—…์˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ํ•ญ์ƒ ์ผ๊ด€์„ฑ์ด์œ ์ง€๋˜์–ด์•ผ ํ•œ๋‹ค. (๋ฌด๊ฒฐ์„ฑ ์ œ์•ฝ์กฐ๊ฑด ๋“ฑ)
- ๋…๋ฆฝ์„ฑ : ์—ฌ๋Ÿฌ Transaction ์ด ์ˆ˜ํ–‰ ๋˜๋”๋ผ๋„ ๊ฐ๊ฐ์˜ Transaction ์€ ์„œ๋กœ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.
- ์ง€์†์„ฑ : Transaction ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜ํ–‰์„ ๋งˆ์น˜๋ฉด ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ DB ์˜๊ตฌ์ ์œผ๋กœ ๋ณด์กด๋˜์–ด์•ผ ํ•œ๋‹ค.

@Transactional

JPA ๋Š” Transaction ์˜ ์›์ž์„ฑ, ์ผ๊ด€์„ฑ, ๋…๋ฆฝ์„ฑ, ์ง€์†์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด @Transactional ์–ด๋…ธํ…Œ์ด์…˜์„ ์ง€์›ํ•œ๋‹ค.
ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์€ Transaction ์ˆ˜ํ–‰ ์‹œ ์ „ํŒŒ ์œ ํ˜•, ๊ฒฉ๋ฆฌ ์ˆ˜์ค€, read-only, Rollback ๊ทœ์น™ ๋“ฑ์„ ์„ค์ • ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Class ํ˜น์€ Method ์— ์ง€์ •ํ•˜์—ฌ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค.
@Transactional
class ProductService {

	@Transactional(readonly = true)
	fun findProduct(id: String): Product {
    	...
    }
}

์ „ํŒŒ ์œ ํ˜•

  • REQUIRED
    • @Transactional ์˜ ๊ธฐ๋ณธ ์ „ํŒŒ ์œ ํ˜• ์„ค์ •์ด๋‹ค. ๋•Œ๋ฌธ์— @Transactional ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ ์‹œ, ์ƒˆ๋กœ์šด Transaction ์„ ์ƒ์„ฑํ•œ๋‹ค.
  • SUPPORTS
    • ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ Transaction ์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๊ธฐ์กด Transction ์„, ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ Transaction ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.
  • MANDATORY
    • ํ™œ์„ฑํ™”๋œ Transaction ์ด ์กด์žฌํ•ด์•ผ ํ•˜๋ฉฐ, ๊ธฐ์กด Transaction ์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋งŒ์•ฝ ํ™œ์„ฑ Transaction ์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒํ•œ๋‹ค.
if (isExistingTransaction()) {
    if (isValidateExistingTransaction()) {
        validateExisitingAndThrowExceptionIfNotValid();
    }
    return existing;
}
throw IllegalTransactionStateException;
  • REQUIRES_NEW
    • ํ˜„์žฌ Transaction ์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๊ธฐ์กด Transaction ์„ ์ข…๋ฃŒํ•˜๊ณ , ์ง„ํ–‰ ์ค‘์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ƒˆ๋กœ์šด Transaction ์„ ์ƒ์„ฑํ•˜์—ฌ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•œ๋‹ค.
  • NOT_SUPPOERTED
    • ํ˜„์žฌ Transaction ์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๊ธฐ์กด Transaction ์„ ์ข…๋ฃŒํ•˜๊ณ , ์ง„ํ–‰ ์ค‘์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ Transaction ์—†์ด ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•œ๋‹ค.
  • NEVER
    • ํ•ด๋‹น ์ „ํŒŒ ์œ ํ˜•์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒฝ์šฐ, ํด๋ž˜์Šค ๋ฐ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ์‹œ ํ™œ์„ฑ๋œ Transaction ์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒํ•œ๋‹ค.
if (isExistingTransaction()) {
    throw IllegalTransactionStateException;
}
return emptyTransaction;
  • NESTED
    • ํ˜„์žฌ Transaction ์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๋ถ€๋ชจ Transaction ์˜ Commit / Rollback ์— ์˜ํ–ฅ์„ ๋ฐ›๊ณ , ์ž์‹ ์˜ Commit / Rollback ์— ๋Œ€ํ•ด์„œ๋Š” ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰, ์ฃผ๋„๊ถŒ์ด ๋ถ€๋ชจ Transaction ์— ์žˆ๋‹ค. 

๊ฒฉ๋ฆฌ ์ˆ˜์ค€

๊ฒฉ๋ฆฌ ์ˆ˜์ค€์€ ACID ํŠน์„ฑ ์ค‘ ํ•˜๋‚˜๋กœ, ๋™์‹œ Transaction ๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€์— ๋Œ€ํ•ด ์„ค์ •ํ•œ๋‹ค.
์ด๋Ÿฌํ•œ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์€ ๋‹ค์Œ์˜ ์˜ํ–ฅ๋ ฅ์„ ๊ฐ€์ง„๋‹ค.

- DIrty Read : ๋™์‹œ Transaction ์˜ Commit ๋˜์ง€ ์•Š์€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์กฐํšŒํ•œ๋‹ค.
- Nonrepeatable Read : ๋™์‹œ Transaction ์ด ๋™์ผํ•œ ํ–‰์„ ์—…๋ฐ์ดํŠธ ๋ฐ ์ปค๋ฐ‹์„ ํ•˜๋Š” ๊ฒฝ์šฐ ํ–‰์„ ์ฝ์„ ๋•Œ ๋‹ค๋ฅธ ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค.
- Phantom Read : ๋‹ค๋ฅธ Transaction ์˜ ๋ฒ”์œ„ ์ค‘ ์ผ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•œ๋‹ค. ํ˜น์€ Commit ํ•˜๋Š” ๊ฒฝ์šฐ ๋ฒ”์œ„์— ๋Œ€ํ•œ Query ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•œ ํ›„ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
  • DEFAULT
    • @Transactional ์˜ ๊ธฐ๋ณธ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋‹ค. ์ด๋Š” RDBMS ์˜ ๊ธฐ๋ณธ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋‹ค.
  • READ_UNCOMMITED
    • ๊ฐ€์žฅ ๋‚ฎ์€ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์œผ๋กœ ๋™์‹œ ์—‘์„ธ์Šค๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค. ๋•Œ๋ฌธ์— ๋™์‹œ์„ฑ ๋ถ€์ž‘์šฉ์ด ๋ชจ๋‘ ๋ฐœ์ƒํ•˜๋Š”๋ฐ, ํ•ด๋‹น ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์œผ๋กœ ์„ค์ •๋˜๋Š” ๊ฒฝ์šฐ ๋™์‹œ Transaction ์ˆ˜ํ–‰ ์‹œ, ๋‹ค๋ฅธ Transaction ์—์„œ Commit ๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ๊ทธ๋ž˜์„œ ์‹คํ–‰ํ•  ๋•Œ ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์œ ์˜ํ•ด์•ผ ํ•œ๋‹ค.
  • READ_COMMITED
    • ๋™์‹œ Transaction ์ˆ˜ํ–‰ ์‹œ ๋‹ค๋ฅธ Transaction ์ด Commit ๋œ ์ดํ›„ ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋„๋ก ํ•˜๋Š” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์œผ๋กœ Dirty Read ๋ฅผ ๋ฐฉ์ง€ํ•œ๋‹ค. ๋‹ค๋งŒ Nonreapeatable Read / Phantom Read ๋Š” ์—ฌ์ „ํžˆ ๋ฐฉ์ง€ํ•˜์ง€ ๋ชปํ•ด ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • REPEATABLE_READ
    • Dirty Read ๋ฐ Nonreapeatable Read ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋‹ค. ์ฆ‰, ๋™์‹œ Transaction ์ˆ˜ํ–‰ ์ค‘ Commit ๋˜์ง€ ์•Š์€ ๋‚ด์šฉ์€ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ๋˜ํ•œ, ์—…๋ฐ์ดํŠธ ์†์‹ค์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋™์‹œ Transaction ์ˆ˜ํ–‰ ์‹œ ๋™์‹œ ์—‘์„ธ์Šค๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • SERIALIZABLE
    • ๋ชจ๋“  ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ Transaction ์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—‘์„ธ์Šค ์†๋„๊ฐ€ ๊ฐ€์žฅ ๋‚ฎ๋‹ค.

'Programming > Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[QueryDSL] NoSuchMethodError Trouble Shooting  (0) 2023.02.22
Criteria API  (0) 2023.01.28
Spring Bean / IoC Container / DI  (1) 2023.01.21
Spring | Spring Framework ?  (0) 2020.08.02
IntelliJ | Spring MVC + Maven ํ”„๋กœ์ ํŠธ ๋งŒ๋“ค๊ธฐ (Oracle)  (0) 2020.07.26