ν΄λΉ κΈμ CS μ€ν°λ μλ£ μ λμΌν©λλ€.
//κ²μνμ κ²μκΈμ μμ νλ λ©μλ
@Transactional
public void removeBoard(Long id)throws Exception{
replyDAO.removeAll(id); //μμ ν κ²μκΈμ λ΅κΈ μμ
boardDAO.deleteBoard(id); //κ²μκΈ μμ
}
λ°μ΄ν°λ² μ΄μ€ κ΄λ¦¬ μμ€ν λλ μ μ¬ν μμ€ν μμ μνΈμμ©μ λ¨μμ΄λ€. μ¬κΈ°μ μ μ¬ν μμ€ν μ΄λ νΈλμμ μ΄ μ±κ³΅κ³Ό μ€ν¨κ° λΆλͺ νκ³ μνΈ λ 립μ μ΄λ©°, μΌκ΄λκ³ λ―Ώμ μ μλ μμ€ν μ μλ―Ένλ€. λ°μ΄ν°μ μ ν©μ±μ 보μ₯νκΈ° μν΄ κ³ μλ λ°©λ²μ΄λ€.
μ΄λ‘ μ μΌλ‘ λ°μ΄ν°λ² μ΄μ€ μμ€ν μ κ°κ°μ νΈλμμ μ λν΄ μμμ±(
Atomicity
), μΌκ΄μ±(Consistency
), λ 립μ±(Isolation
), μꡬμ±(Durability
)μ 보μ₯νλ€. μ΄ μ±μ§μ 첫κΈμλ₯Ό λ° ACIDλΌ λΆλ₯Έλ€.
μμμ±(Atomicity)
:μΌκ΄μ±(Consistency)
: κ° λ°μ΄ν° νΈλμμ
μ΄ λ°μ΄ν°λ² μ΄μ€λ₯Ό μΌκ΄μ± μλ μνμμ μΌκ΄μ± μλ μνλ‘ μ΄λν΄μΌ ν¨μ μλ―Ένλ€. μ¦ νΈλμμ
μ΄ μ±κ³΅μ μΌλ‘ μλ£νλ©΄ μΈμ λ λμΌν λ°μ΄ν°λ² μ΄μ€ μνλ‘ μ μ§νλ κ²μ μλ―Ένλ€.λ
립μ±(Isolation)
: νΈλμμ
μ μν μ λ€λ₯Έ νΈλμμ
μ μ°μ° μμ
μ΄ λΌμ΄λ€μ§ λͺ»νλλ‘ λ³΄μ₯νλ κ²μ μλ―Ένλ€. μ΄κ²μ νΈλμμ
λ°μ μλ μ΄λ€ μ°μ°λ μ€κ° λ¨κ³μ λ°μ΄ν°λ₯Ό λ³Ό μ μμμ μλ―Ένλ€. μ¬λ¬ νΈλμμ
μ΄ λμμ λ°μνλ κ²½μ° μ΅μ’
μνλ νΈλμμ
μ΄ κ°λ³μ μΌλ‘ λ°μν κ²κ³Ό κ°μμΌ νλ€. μ¦, λ°μ΄ν°λ² μ΄μ€λ μ€νΈλ μ€ ν
μ€νΈλ₯Ό ν΅κ³Όν΄μΌ νλ€. μ¦, κ³ΌλΆνλ‘ μΈν΄ μλͺ»λ λ°μ΄ν°λ² μ΄μ€ νΈλμμ
μ΄ λ°μνμ§ μμμΌ νλ€.μ§μμ±(Durability)
: μ±κ³΅μ μΌλ‘ μνλ νΈλμμ
μ μμν λ°μ(κΈ°λ‘)λμ΄μΌ ν¨μ μλ―Ένλ€. νΈλμμ
μ λ‘κ·Έμ λͺ¨λ κ²μ΄ μ μ₯λ νμλ§ commit μνλ‘ κ°μ£Όλ μ μλ€. λ°μ΄ν°λ² μ΄μ€ λ΄μ λ°μ΄ν°λ νΈλμμ
μ κ²°κ³Όλ‘λ§ λ³κ²½λμ΄μΌ νλ©° μΈλΆ μν₯μ μν΄ λ³κ²½λ μ μμ΄μΌ νλ€. μλ₯Ό λ€μ΄ μννΈμ¨μ΄ μ
λ°μ΄νΈλ‘ μΈν΄ λ°μ΄ν°κ° μ€μλ‘ λ³κ²½λκ±°λ μμ λμ§ μμμΌ νλ€.ACID - μν€λ°±κ³Ό, μ°λ¦¬ λͺ¨λμ λ°±κ³Όμ¬μ
λ§μ½ 쿼리 νλκ° μ€ν¨νλ©΄, λ°μ΄ν°λ² μ΄μ€ μμ€ν μ μ 체 νΈλμμ λλ μ€ν¨ν 쿼리λ₯Ό λ‘€λ°±νλ€.
νΈλμμ
μ μ§μνλ λ°μ΄ν°λ² μ΄μ€λ₯Ό νΈλμμ
λ λ°μ΄ν°λ² μ΄μ€(transactional database
)λΌκ³ λΆλ₯Έλ€.
νμ¬ λλΆλΆμ κ΄κ³ν λ°μ΄ν°λ² μ΄μ€ κ΄λ¦¬μμ€ν μ νΈλμμ λ°μ΄ν°λ² μ΄μ€μ΄λ€.
λ°μ΄ν°λ² μ΄μ€ νΈλμμ - μν€λ°±κ³Ό, μ°λ¦¬ λͺ¨λμ λ°±κ³Όμ¬μ
νΉμ μ€νλ¨μμμ μ€λ₯ λ°μμ μ 체 μ€ν λ΄μ©μ λ‘€λ°±
ν΄μ£Όλ κΈ°λ₯
Connection connection=dataSource.getConnection()
try(connection){
connection.setAutoCommit(false);
// λΉμ¦λμ€ λ‘μ§ μν
connection.commit();
}catch(SQLException e){
connection.rollback();
}finally{
connection.close()
}
setAutoCommit(false)
λ₯Ό ν΅ν΄ νΈλμμ
μ μ§μ κ΄λ¦¬ν μ μκ² λμλ€.컀λ°
μ νκ³ , μμΈ λ°μμ λ‘€λ°±
μ νκ³ μλ€.Connection
μ€λΈμ νΈλ₯Ό νλ² μμ± ν κ³μ λ©μλμ νλΌλ―Έν°λ‘ μ λ¬νλ€κ° DAO
λ₯Ό νΈμΆν λ μ¬μ©νλ€Connection
μ€λΈμ νΈλ₯Ό νΉλ³ν μ μ₯μ
μ 보κ΄ν΄λκ³ ,DAO
μ λ©μλμμ νΈλμμ
μ΄ νμν λConnection
μ κ°μ Έλ€κ° μ¬μ©νλ€.TransactionSynchronizationManager
νΈλμμ λκΈ°ν μ μ₯μ
μ€λ λ
λ§λ€ λ
립μ μΌλ‘ Connection
μ€λΈμ νΈλ₯Ό μ μ₯νκ³ κ΄λ¦¬λ©ν°μ€λ λ
νκ²½μμλ μΆ©λ x
μ΄μ μ¬λ¬ 쿼리λ₯Ό ν λ‘컬 νΈλμμ μ κ΄λ¦¬ κ°λ₯νλ€.
νλΌλ―Έν°λ μ κ±°ν μ μλ€.
private DeataSource dataSource;
// Connectionμ μμ±ν λ μ¬μ©ν DataSourceλ₯Ό DI λ°λλ€
public void setDataSource(DataSource dataSource){
this.dataSource=dataSource;
}
public void method()throws Exception{
// 1. λκΈ°ν μμ
μ΄κΈ°ν
TransactionSynchronizationManager.initSynchronization();
// 2. DB 컀λ₯μ
μ μμ±νκ³ νΈλμμ
μ μμ
Connection c=DataSourceUtils.getConnection(dataSource);
c.setAuthCommit(false);
try{
// 3. λΉμ¦λμ€ λ‘μ§ μν
c.commit();
}catch(Exception e){
c.rollback();
throw e;
}finally{
DataSourceUtils.releaseConnection(c,dataSource);
// 4. λκΈ°ν μμ
μ’
λ£ λ° μ 리
TransactionSynchronizationManager.unbindResource(this.dataSource);
TransactionSynchronizationManager.clearSynchronization();
}
}
DataSourceUtils
μ μ¬μ©ν΄ Connection
μ€λΈμ νΈλ₯Ό κ°μ Έμ¨λ€. μ¦, μμ§ Data μ κ·Ό κΈ°μ
μ μμ‘΄μ μ΄λ€.
μ€νλ§μ Data μ κ·Ό κΈ°μ
μ λ
립μ μΈ
νΈλμμ
μ μ¬μ© ν μ μλ€.
κΈ°μ λ³λ‘ κ°μ Έμ€λ νΈλμμ ννλ§ λ€λ₯Ό λΏ, νΈλμμ κΈ°λ₯μ κ°κΈ° λλ¬Έμ μΆμνκ° κ°λ₯νλ€.
PlatformTransactionManager
JPA
, JDBC
λ± λ€μν κΈ°μ μ νΈλμμ
μ μΆμν
νΈλμμ
κ²½κ³μ€μ
μ΄ κ°λ₯ν΄μ‘λ€public void method()throws Exception{
// 1.μ¬μ©ν DB(JDBC)μ DataSourceλ₯Ό μμ±μμ λ£μ΄ νΈλμμ
μΆμ μ€λΈμ νΈ μμ±
PlatformTransactionManager transactionManager=new DataSourceTransactionManager(dataSource);
TransactionStatus status=transactionManager.getTransaction(new DefaultTransactionDefinition()); //νΈλμμ
μμ
try{
// 2. λΉμ¦λμ€ λ‘μ§ μν
transactionManager.commit(status);
}catch(Exception e){
transactionManager.rollback(status);
throw e;
}
}
JDBC
λμ JPA
λ₯Ό μ΄μ©νλ λ²PlatformTransactionManager transactionManager=new DataSourceTransactionManager(dataSource);
μμ
PlatformTransactionManager transactionManager=new JpaTransactionManager();
μ΄λ κ² λ°κΏμ£ΌκΈ°λ§ νλ©΄ λλ€.
μ¬μ ν μμ λΉμ¦λμ€ λ‘μ§κ³Όλ λ€λ₯Έ κ΄μ¬μ¬μ μΌ(DB μ κ·Ό κ΄λ ¨)μ μννλ€. μ½λκ° κΉλνμ§ μλ€.
@Transactional
)μμ€μ½λμ μ§μ νΈλμμ κ΄λ ¨ λ‘μ§μ λ£μ΄λμ§ μκ³ λΉμ§λμ€ λ‘μ§μμ μμ ν λΆλ¦¬νλ λ°©μμ΄λ€.
μ΄ λ°©μμ μ¬μ©νλ©΄ νλ‘κ·Έλλ°μ μν νΈλμμ μμ λμ¨ λ¨μ μΈ νΈλμμ μ½λ μ€λ³΅ λ¬Έμ , μμ€μ½λ μ μ§λ³΄μμ λ¬Έμ λ₯Ό λͺ¨λ ν΄κ²°ν μ μλ€.
νΈλμμ μ΄λΌλ ν‘λ¨ κ΄μ¬μ¬λ₯Ό λΉμ§λμ€ λ‘μ§μμ μμ ν λΆλ¦¬νκΈ° λλ¬Έμ SRP κ΄μ μμ λ΄€μλλ μ ν©νκ³ λ§μ μμ νΈλμμ λ‘μ§μ μ μ©νκΈ°μλ ν©λ¦¬μ μ΄λ€.
Spring
μμλ AOP
λ₯Ό μ¬μ©ν΄μ μ μΈμ νΈλμμ
μ ꡬννκ³ μλ€.
AbstractPlatformTransactionManager
μμ ν©ν 리 λ©μλ ν¨ν΄μ μ¬μ©ν΄μ μ¬λ¬ PlatformTransactionManager
μ νμ₯νλ€.TransactionInterceptor
λ₯Ό ν΅ν΄ νΈλμμ
κ²½κ³λ₯Ό μ€μ νκ³ μ¬κΈ°μμ μ£Όμ
λ PlatformTransactionManager
λ₯Ό μ¬μ©νλ€.SpringTransactionAnnotationParser
λ₯Ό ν΅ν΄ @Transactional
κ΄λ ¨ μμ±μ νμ±νλ€.AbstractAutoProxyCreator
μ μν΄ Proxy
λ‘ μμ±λκ³ μ€μ ν΄λΌμ΄μΈνΈκ° νκΉμ μ κ·Όν λλ Proxy
λ₯Ό κ±°μ³ TransactionInterceptor
λ₯Ό μ¬μ©ν΄ νΈλμμ
μ μ΄κ³ μ€μν건, μ΄μ μ΄λ
Έν
μ΄μ
μΌλ‘ νΈλμμ
κ΄λ¦¬κ° κ°λ₯ν΄μ‘λ€λ κ²μ΄λ€!!
@Transactional
ν΄λμ€ μ£Όμ λ¬Έμ λ²μ
/*
κ°λ³ λ©μλ λλ ν΄λμ€μ νΈλμμ
νΉμ±μ μ€λͺ
ν©λλ€.
μ΄ μ£Όμμ΄ ν΄λμ€ μμ€μμ μ μΈλλ©΄ μ μΈνλ ν΄λμ€ λ° ν΄λΉ νμ ν΄λμ€μ λͺ¨λ λ©μλμ κΈ°λ³Έκ°μΌλ‘ μ μ©λ©λλ€. ν΄λμ€ κ³μΈ΅μ μμ ν΄λμ€μλ μ μ©λμ§ μμ΅λλ€. μμλ λ©μλλ νμ ν΄λμ€ μμ€ μ£Όμμ μ°Έμ¬νκΈ° μν΄ λ‘컬μμ λ€μ μ μΈν΄μΌ ν©λλ€. λ©μλ κ°μμ± μ μ½μ λν μμΈν λ΄μ©μ μ°Έμ‘° 맀λ΄μΌμ νΈλμμ
κ΄λ¦¬ μΉμ
μ μ°Έμ‘°νμμμ€.
μ΄ μ£Όμμ μΌλ°μ μΌλ‘ Springμ org.springframework.transaction.interceptor.RuleBasedTransactionAttribute ν΄λμ€μ μ§μ λΉκ΅ν μ μμΌλ©° μ€μ λ‘ AnnotationTransactionAttributeSourceλ μ΄ μ£Όμμ μμ±μ RuleBasedTransactionAttributeμ μμ±μΌλ‘ μ§μ λ³ννλ―λ‘ Springμ νΈλμμ
μ§μ μ½λλ μ£Όμμ λν΄ μ νμκ° μμ΅λλ€.
Attribute Semantics
μ΄ μ£Όμμ μ¬μ©μ μ§μ λ‘€λ°± κ·μΉμ΄ ꡬμ±λμ§ μμ κ²½μ° νΈλμμ
μ RuntimeException λ° Error μ λ‘€λ°±λμ§λ§ νμΈλ μμΈμμλ λ‘€λ°±λμ§ μμ΅λλ€.
λ‘€λ°± κ·μΉμ μ§μ λ μμΈκ° throwλ λ νΈλμμ
μ λ‘€λ°±ν΄μΌ νλμ§ μ¬λΆλ₯Ό κ²°μ νλ©° κ·μΉμ ν¨ν΄μ κΈ°λ°μΌλ‘ ν©λλ€. ν¨ν΄μ νμ¬ μμΌλμΉ΄λ μ§μμ΄ μλ μ κ·νλ ν΄λμ€ μ΄λ¦ λλ μμΈ μ ν(Throwableμ νμ ν΄λμ€μ¬μΌ ν¨)μ λν μ κ·νλ ν΄λμ€ μ΄λ¦μ νμ λ¬Έμμ΄μΌ μ μμ΅λλ€. μλ₯Ό λ€μ΄ "javax.servlet.ServletException" λλ "ServletException" κ°μ javax.servlet.ServletException λ° ν΄λΉ νμ ν΄λμ€μ μΌμΉν©λλ€.
λ‘€λ°± κ·μΉμ κ°κ° ν¨ν΄μ ν΄λμ€ μ°Έμ‘° λλ λ¬Έμμ΄λ‘ μ§μ ν μ μλλ‘ νλ rollbackFor/noRollbackFor λ° rollbackForClassName/noRollbackForClassNameμ ν΅ν΄ ꡬμ±ν μ μμ΅λλ€. μμΈ μ νμ΄ ν΄λμ€ μ°Έμ‘°λ‘ μ§μ λλ©΄ μ κ·νλ μ΄λ¦μ΄ ν¨ν΄μΌλ‘ μ¬μ©λ©λλ€. κ²°κ³Όμ μΌλ‘ @Transactional(rollbackFor = example.CustomException.class)μ @Transactional(rollbackForClassName = "example.CustomException")κ³Ό λμΌν©λλ€.
κ²½κ³ : ν¨ν΄μ΄ μΌλ§λ ꡬ체μ μΈμ§, ν¨ν€μ§ μ 보λ₯Ό ν¬ν¨ν μ§ μ¬λΆλ₯Ό μ μ€νκ² κ³ λ €ν΄μΌ ν©λλ€
(νμ μ¬νμ μλ).
μλ₯Ό λ€μ΄ "μμΈ"λ κ±°μ λͺ¨λ νλͺ©κ³Ό μΌμΉνλ©° λ€λ₯Έ κ·μΉμ μ¨κΈΈ μ μμ΅λλ€. "Exception"μ΄ κ²μ¬λ λͺ¨λ μμΈμ λν κ·μΉμ μ μνλ €λ κ²½μ° "java.lang.Exception"μ΄ μ νν©λλ€. "BaseBusinessException"κ³Ό κ°μ λ³΄λ€ κ³ μ ν μμΈ μ΄λ¦μ μ¬μ©νλ©΄ μμΈ ν¨ν΄μ λν΄ μμ ν ν΄λμ€ μ΄λ¦μ μ¬μ©ν νμκ° μμ κ²μ
λλ€.
λν λ‘€λ°± κ·μΉμΌλ‘ μΈν΄ μ μ¬ν μ΄λ¦μ μμΈ λ° μ€μ²© ν΄λμ€μ λν΄ μλνμ§ μμ μΌμΉκ° λ°μν μ μμ΅λλ€. μ΄λ throwλ μμΈμ μ΄λ¦μ λ‘€λ°± κ·μΉμ λν΄ κ΅¬μ±λ μμΈ ν¨ν΄μ΄ ν¬ν¨λ κ²½μ° throwλ μμΈκ° μ§μ λ λ‘€λ°± κ·μΉκ³Ό μΌμΉνλ κ²μΌλ‘ κ°μ£ΌλκΈ° λλ¬Έμ
λλ€.
μλ₯Ό λ€μ΄, com.example.CustomExceptionμμ μΌμΉνλλ‘ κ΅¬μ±λ κ·μΉμ΄ μ£Όμ΄μ§λ©΄ ν΄λΉ κ·μΉμ com.example.CustomExceptionV2λΌλ μμΈ(CustomExceptionκ³Ό λμΌν ν¨ν€μ§μ μμ§λ§ μΆκ° μ λ―Έμ¬κ° μλ μμΈ) λλ comμ΄λΌλ μμΈμ μΌμΉν©λλ€. example.CustomException$AnotherException(CustomExceptionμμ μ€μ²© ν΄λμ€λ‘ μ μΈλ μμΈ).
μ΄ μ£Όμμ μλ λ€λ₯Έ μμ±μ μλ―Έμ λν νΉμ μ 보λ TransactionDefinition λ° org.springframework.transaction.interceptor.TransactionAttribute javadocμ μ°Έμ‘°νμμμ€.
**νΈλμμ
κ΄λ¦¬**
μ΄ μ£Όμμ μΌλ°μ μΌλ‘ org.springframework.transaction.PlatformTransactionManagerμ μν΄ κ΄λ¦¬λλ μ€λ λ λ°μ΄λ νΈλμμ
κ³Ό ν¨κ» μλνμ¬ νμ¬ μ€ν μ€λ λ λ΄μ λͺ¨λ λ°μ΄ν° μ‘μΈμ€ μμ
μ νΈλμμ
μ λ
ΈμΆν©λλ€. μ°Έκ³ : μ΄κ²μ λ©μλ λ΄μμ μλ‘ μμλ μ€λ λλ‘ μ νλμ§ μμ΅λλ€.
λλ μ΄ μ£Όμμ μ€λ λ λ‘컬 λ³μ λμ Reactor 컨ν
μ€νΈλ₯Ό μ¬μ©νλ org.springframework.transaction.ReactiveTransactionManagerμ μν΄ κ΄λ¦¬λλ λ°μ νΈλμμ
μ ꡬλΆν μ μμ΅λλ€. κ²°κ³Όμ μΌλ‘ λͺ¨λ μ°Έμ¬ λ°μ΄ν° μ‘μΈμ€ μμ
μ λμΌν 리μ‘ν°λΈ νμ΄νλΌμΈμ λμΌν Reactor 컨ν
μ€νΈ λ΄μμ μ€νλμ΄μΌ ν©λλ€.
Since:1.2
See Also :org.springframework.transaction.interceptor.TransactionAttribute, org.springframework.transaction.interceptor.DefaultTransactionAttribute, org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
μκ°:μ½λ¦° μΌνλ μλ, μ λ₯΄κ² νλ¬, μ λΈλλ, λ§ν¬ ν루μΉ
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
// μ¬μ©ν νΈλμμ
κ΄λ¦¬μ
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
String[] label() default {};
// μ νμ μ ν μ€μ
Propagation propagation() default Propagation.REQUIRED;
// μ νμ 격리 μμ€
Isolation isolation() default Isolation.DEFAULT;
// νΈλμμ
νμ μμ
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
String timeoutString() default "";
// μ½κΈ°/μ°κΈ° vs μ½κΈ° μ μ© νΈλμμ
boolean readOnly() default false;
// λ‘€λ°±μ΄ μνλμ΄μΌ νλ, μ νμ μΈ μμΈ ν΄λμ€μ λ°°μ΄
Class<? extends Throwable>[] rollbackFor() default {};
// λ‘€λ°±μ΄ μνλμ΄μΌ νλ, μ νμ μΈ μμΈ ν΄λμ€ μ΄λ¦μ λ°°μ΄
String[] rollbackForClassName() default {};
// λ‘€λ°±μ΄ μνλμ§ μμμΌ νλ, μ νμ μΈ μμΈ ν΄λμ€μ λ°°μ΄
Class<? extends Throwable>[] noRollbackFor() default {};
// λ‘€λ°±μ΄ μνλμ§ μμμΌ νλ, μ νμ μΈ μμΈ ν΄λμ€ μ΄λ¦μ λ°°μ΄
String[] noRollbackForClassName() default {};
}
Isolation Level
)DEFAULT
:λ°μ΄ν° λ² μ΄μ€μμ μ€μ λ κΈ°λ³Έ 격리 μμ€μ λ°λ¦
λλ€.
READ_UNCOMMITED
: νΈλμμ
μ΄ μμ§ μ»€λ°λμ§ μμ λ°μ΄ν°λ₯Ό μ½μ μ μμ΅λλ€.
READ_COMMITED
: Dirty Read λ₯Ό λ°©μ§νκΈ° μν΄ Commit λ λ°μ΄ν°λ§ μ½μ μ μμ΅λλ€.
REPEATABLE READ
: νΈλμμ
μ΄ μλ£λ λκΉμ§ μ‘°νν λͺ¨λ λ°μ΄ν°μ shared lockμ΄ κ±Έλ¦¬λ―λ‘ νΈλμμ
μ΄ μ’
λ£λ λκΉμ§ λ€λ₯Έ νΈλμμ
μ κ·Έ μμμ ν΄λΉνλ λ°μ΄ν°λ₯Ό μμ ν μ μμ΅λλ€.
SERIALIZABLE
: κ°μ₯ μ격ν νΈλμμ
격리μμ€μΌλ‘, μλ²½ν μ½κΈ° μΌκ΄μ± λͺ¨λλ₯Ό μ 곡ν©λλ€. μ΄ κ²©λ¦¬ μμ€μμλ PHANTOM READ μνκ° λ°μνμ§ μμ§λ§ λμμ± μ²λ¦¬ μ±λ₯μ΄ κΈκ²©ν λ¨μ΄μ§ μ
μμ΅λλ€.
Propagation
)REQUIRED
: μ΄λ―Έ μμλ νΈλμμ
μ΄ μμΌλ©΄ μ°Έμ¬νκ³ , μμΌλ©΄ μλ‘μ΄ νΈλμμ
μ μμν©λλ€. (λν΄νΈ μμ±)SUPPORTS
: μ΄λ―Έ μμλ νΈλμμ
μ΄ μμΌλ©΄ μ°Έμ¬νκ³ , μμΌλ©΄ νΈλμμ
μμ΄ μ²λ¦¬ν©λλ€.REQUIRED_NEW
: νμ μλ‘μ΄ νΈλμμ
μ μμν©λλ€. μ΄λ―Έ μ§νμ€μΈ νΈλμμ
μ΄ μλ€λ©΄ μ μ 보λ₯μν΅λλ€.MANDATORY
: μ΄λ―Έ μμλ νΈλμμ
μ΄ μμΌλ©΄ μ°Έμ¬νκ³ , μμΌλ©΄ μλ‘μ΄ νΈλμμ
μ μμνλ λμ μμΈλ₯Ό λ°μμν΅λλ€. νΌμμλ λ
립μ μΌλ‘ μνλλ©΄ μλλ κ²½μ°μ μ¬μ©λ©λλ€.NOT_SUPPORTED
: νΈλμμ
μ μ¬μ©νμ§ μκ³ μ²λ¦¬νλλ‘ ν©λλ€. μ΄λ―Έ μ§νμ€μΈ νΈλμμ
μ΄ μλ€λ©΄ μ μ 보λ₯μν΅λλ€.NEVER
: νΈλμμ
μ μ¬μ©νμ§ μλλ‘ κ°μ μν΅λλ€. μ΄λ―Έ μ§νμ€μΈ νΈλμμ
λν νμ©νμ§ μμΌλ©°, μλ€λ©΄ μμΈλ₯Ό λ°μμν΅λλ€.NESTED
: μ΄λ―Έ μ€νμ€μΈ νΈλμμ
μ΄ μλ€λ©΄ μ€μ²©νμ¬ νΈλμμ
μ μ§νν©λλ€. λΆλͺ¨ νΈλμμ
μ μ€μ²© νΈλμμ
μ μν₯μ μ£Όμ§λ§ μ€μ²© νΈλμμ
μ λΆλͺ¨ νΈλμμ
μ μν₯μ μ£Όμ§ μμ΅λλ€.readOnly
μ΅μ
readOnly
μμ±μ ν΅ν΄ νΈλμμ
μ μ½κΈ° μ μ©μΌλ‘ μ€μ ν μ μλ€.JPA
μ κ²½μ°, ν΄λΉ μ΅μ
μ true
λ‘ μ€μ νκ² λλ©΄ νΈλμμ
μ΄ μ»€λ°λμ΄λ μμμ± μ»¨ν
μ€νΈλ₯Ό νλ¬μνμ§ μλλ€. νλ¬μν λ μνλλ μν°ν°μ μ€λ
μ· λΉκ΅ λ‘μ§μ΄ μνλμ§ μμΌλ―λ‘ μ±λ₯μ ν₯μ μν¬ μhttps://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html
https://programmer-study.tistory.com/19
https://sup2is.github.io/2021/11/11/about-spring-transaction.html
https://towardsdatascience.com/database-basics-acid-transactions-bf4d38bd8e26
λΉμ¦λμ€ λ‘μ§μ΄ νΈλμμ
μ²λ¦¬λ₯Ό νμλ‘ ν λ, νΈλμμ
μ²λ¦¬ μ½λμ λΉμ¦λμ€ λ‘μ§μ΄ 곡쑴νλ€λ©΄ μ½λ μ€λ³΅μ΄ λ°μνκ³ λΉμ¦λμ€ λ‘μ§μ μ§μ€νκΈ° μ΄λ ΅λ€. λ°λΌμ νΈλμμ
μ²λ¦¬μ λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬ν μ μλ μ μΈμ
νΈλμμ
λ°©μμ μμ£Ό μ¬μ©νλ€.
@Transactional
μ λμ μ리λ?@Transactional
μ λ©μλ λλ ν΄λμ€μ λͺ
μνλ©΄
AOP
λ₯Ό ν΅ν΄
Target
μ΄ μμνκ³ μλ μΈν°νμ΄μ€ λλ Target
κ°μ²΄λ₯Ό μμν Proxy
κ°μ²΄κ° μμ±λλ©°,
Proxy
κ°μ²΄μ λ©μλλ₯Ό νΈμΆνλ©΄
Target
λ©μλ μ νλ‘ νΈλμμ
μ²λ¦¬λ₯Ό μννλ€.
@Transactional
μ μ¬μ©ν λ μ£Όμν μ μ?could not initialize proxy[com.wooteco.sokdak.hashtag.domain.Hashtag#3]-no Session
org.hibernate.LazyInitializationException:could not initialize proxy[com.wooteco.sokdak.hashtag.domain.Hashtag#3]-no Session
...
Proxy
κ°μ²΄μ Target Method
κ° λ΄λΆ λ©μλλ₯Ό νΈμΆνλ©΄ μ€μ λ©μλκ° νΈμΆλκΈ° λλ¬Έμ
Inner Method
μμ @Transactional
μ΄λ
Έν
μ΄μ
μ΄ μ μ©λμ§ μλ κ²μ μ£Όμν΄μΌ νλ€.
@Transactional
μ΄λ
Έν
μ΄μ
μ λΆμ΄λ©΄ νΈλμμ
μ²λ¦¬λ₯Ό μν΄ Proxy
κ°μ²΄λ₯Ό μμ±νλλ°,
Proxy
λ Target Class
λ₯Ό μμνμ¬ μμ±λλ€.
λ°λΌμ μμμ΄ λΆκ°λ₯ν Private λ©μλ
μ κ²½μ° @Transactional
μ΄λ
Έν
μ΄μ
μ μ μ©ν μ μλ€.
νλ‘μ κ΄λ ¨ νΈλ¬λΈμν
[Hibernate / JPA ] LazyLoading | No Session μλ¬μ λν΄μ
@Transactional
μ μ μ©νλ©΄ μ΄λ€ μμ² νλ¦μ΄ λ°μνλμ§ μ€λͺ
νλΌ.νΈλμμ μ ν μμ€μ λ°λΌ λ¬λΌμ§λ€.
λ§μ½ κΈ°λ³Έ μ΅μ
μΈ REQUIRED
λ₯Ό κ°μ Έκ°λ€λ©΄ λ‘컬 νΈλμμ
3κ°κ° λͺ¨λ λΆλͺ¨ νΈλμμ
μΈ Aμ ν©λ₯νμ¬ μνλλ€.
κ·Έλμ λΆλͺ¨ νΈλμμ
μ΄λ λ‘컬 νΈλμμ
3κ°λ λͺ¨λ κ°μ νΈλμμ
μ΄λ―λ‘ μ΄λ νλμ λ‘μ§μμλ λ¬Έμ κ° λ°μνλ©΄ μ λΆ λ‘€λ°±
μ΄ λλ€.