개요


1. 트랜잭션을 생성하기 전까지 (AOP 기반 동작의 시작점)


2. 트랜잭션 생성, 데이터베이스 커넥션 가져오기

  1. createTransactionIfNecessary(..)는 트랜잭션을 필요한 경우에만 생성하는 동작을 수행합니다. 호출 전 동작은 아래와 같습니다.

    <aside> 💡 Map, ConcurrentMap을 활용해 접근이 잦은 객체를 캐싱하는 패턴이 많이 보이네요 ❗

    </aside>

  2. createTransactionIfNecessary(..)를 호출하고, TransacitonInfo 인스턴스를 반환합니다. (2번부터 6번까진 모두 createTransactionIfNecessary(..) 메서드 내부에서 일어납니다)

    *Create a transaction if necessary based on the given TransactionAttribute. Allows callers to perform custom TransactionAttribute lookups through the TransactionAttributeSource.

    필요한 경우 주어진 TransactionAttribute를 기반으로 트랜잭션을 생성합니다. TransactionAttributeSource를 통해 호출자가 사용자 지정 TransactionAttribute 조회를 수행할 수 있습니다.

  3. startTransaction()를 호출해 앞서 생성했던 새로운 트랜잭션을 시작합니다.

    // AbstractPlatformTransactionManager.java
    /**
     * Start a new transaction.
     */
    private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
    		boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
    
    		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    		DefaultTransactionStatus status = newTransactionStatus(
    				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    		**doBegin(transaction, definition);**
    		prepareSynchronization(status, definition);
    		return status;
    }
    
  4. getJpaDialect()를 통해 HibernateJpaDialect 인스턴스를 가져온 뒤 beginTransaction(..)를 호출합니다. 이를 통해 HibernateJpaDialect.SessionTransactionData 인스턴스가 반환됩니다.

    // JpaTransactionManager.java
    @Override
    	protected void doBegin(Object transaction, TransactionDefinition definition) {
    		JpaTransactionObject txObject = (JpaTransactionObject) transaction;
    		...
    		try {
    			EntityManager em = txObject.getEntityManagerHolder().getEntityManager();
    
    			// Delegate to JpaDialect for actual transaction begin.
    ****			int timeoutToUse = determineTimeout(definition);
    			**Object transactionData = getJpaDialect().beginTransaction(em,**
    					**new JpaTransactionDefinition(definition, timeoutToUse, txObject.isNewEntityManagerHolder()));**
    				...	
    		}
    
    		...
    	}
    
  5. entityManager.getTransaction().begin()를 호출해 JPA 전체 컨텍스트를 준비합니다.

    // HibernateJpaDialect.java
    @Override
    public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
    		throws PersistenceException, SQLException, TransactionException {
    	...
    	// Standard JPA transaction begin call for full JPA context setup...
    	**entityManager.getTransaction().begin();
    	...**
    }
    
    ...
    
    // LogicalConnectionManagedImpl.java
    @Override
    public void begin() {
    	initiallyAutoCommit = !doConnectionsFromProviderHaveAutoCommitDisabled() && determineInitialAutoCommitMode(
    			**getConnectionForTransactionManagement()** );
    	super.begin();
    }