[Index](../README.md) · [Propagation →](02-propagation.md) # 1. What `@Transactional` actually does `@Transactional` is an AOP proxy. That single fact predicts every failure in [chapter 5](05-six-silent-failures.md), and it is the same mechanism as [Spring AOP](../../../spring-boot-demo/spring-aop) generally. When a method carrying the annotation is called **through the proxy**, an interceptor: 1. asks the `PlatformTransactionManager` for a transaction, according to the propagation rule; 2. invokes the target method; 3. on a normal return, commits; 4. on a `RuntimeException` or `Error`, rolls back; 5. on a checked `Exception`, **commits** and rethrows. Step 5 is not a typo. See [chapter 5](05-six-silent-failures.md). ## Logical versus physical The distinction that makes propagation comprehensible: - A **logical transaction** is one `@Transactional` scope — one annotated method call. - A **physical transaction** is one real database transaction with one connection, one `BEGIN` and one `COMMIT`. `REQUIRED` maps many logical scopes onto one physical transaction. `REQUIRES_NEW` gives each scope its own. Everything else is a variation on that theme. ## Seeing which is which `TransactionSynchronizationManager` is public API and answers this anywhere in application code: ```java TransactionSynchronizationManager.isActualTransactionActive(); // is there a PHYSICAL one? TransactionSynchronizationManager.getCurrentTransactionName(); // whose scope started it? TransactionSynchronizationManager.isCurrentTransactionReadOnly(); TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); ``` The transaction *name* is the most useful and least known of these. A method that joined its caller's transaction reports the **caller's** name; a method that started its own reports its own. That one string distinguishes joining from starting without reading any documentation. ## The log to turn on ```yaml logging.level.org.springframework.orm.jpa.JpaTransactionManager: DEBUG logging.level.org.springframework.transaction.interceptor: TRACE ``` which narrates the whole thing in the transaction manager's own words: ``` Creating new transaction with name [...OuterService.serializableScope]: PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE Participating in existing transaction Initiating transaction commit ``` `Creating new transaction` versus `Participating in existing transaction` is the answer to most questions people ask about propagation. ## Method visibility `@Transactional` works on `public` methods, and since Spring 6.0 also on `protected` and package-private ones **when the proxy is class-based** (which is Spring Boot's default). It never works on `private` methods, and with interface-based proxies the method must be public and declared on the interface.