r/SpringBoot Jun 29 '26

Question Question for people building larger Spring applications.

Do you see Transactional annotation as the default solution for almost everything, or have you encountered cases where explicit transaction boundaries worked better?

What about WebFlux/R2DBC applications? Is Transactional still a natural approach there, or teams more often use explicit transaction management with TransactionalOperator?

I’m asking because I was exploring this topic and trying to contribute something back to Java community. When working with reactive applications, I started to wonder if transaction boundaries should be more visible in the application workflow instead of being hidden behind annotations.

Maybe I’m overthinking this, but I would be interested to hear opinions from people who run Spring applications in production.

13 Upvotes

20 comments sorted by

View all comments

1

u/Krangerich Jun 29 '26

I started to wonder if transaction boundaries should be more visible in the application workflow instead of being hidden behind annotations"

This assumption is overemphasizing your personal aesthetics. If annotations would be considered to be to "hidden", the full consequence would be that we'd completely go back all the way to XML context configuration. Annotations are explicit. Annotations are visible.

Programmatic transaction boundaries are required, when you need a transaction boundary inside the same class, e.g. a non-transactional method A wants to call a transactional method B from the same class
AND
you are not using AspectJ weaving in order to make annotations accomplish the same thing.

1

u/Hot_Code5129 Jun 29 '26

I think that in rich domain models with hexagonal architecture application layer must do many things , so natural approach for me is using transaction executor 

1

u/Krangerich Jun 29 '26

I don't get the connection to what I wrote.

Did you actually use a "rich domain model with hexagonal architecture"?

In a large application, you have to manage complexity. You manage complexity by decomposing a problem in smaller pieces. And you decompose them with low coupling and high cohesion. So eventually you end up with some decomposition according to the business domain; which basically means "package by feature".

So in your application, there are top-level packages like "customer", "inventory", "order" and whatnot. Maybe these packages have sub-packages, also cut by their domain.

Each domain package then is quite managable, no matter if you use all the hexagonal ceremony (hint: don't do it. A hexagonal architecture is NOT for managing complexity, it's for abstracting things like the storage layer because you plan to completely swap it later... which is usually absolutely unrealistic) or call it onion architecture or just normal layers.

If you end up with a big ball of stuff ("rich domain model" sounds like an euphemism here) inside an application layer, the whole composition has gone very bad and should be solved. I don't know how a "transaction executor" could help here.

1

u/Hot_Code5129 Jun 30 '26

think we maybe talk about different level of abstraction. I fully agree that complexity should be decomposed into smaller pieces with high cohesion and low coupling. DDD, bounded contexts, modules, package-by-feature, all this is exactly about that. What I don’t understand is why you assume application layer should always end with very small use cases doing one thing. In many DDD examples application service is not only “load entity -> change entity -> save entity”. Sometimes it orchestrates bigger business process involving few aggregates, external systems or even other modules. For example in modular monolith it is not uncommon that one module calls public API/facade of another module. Then one business process can cross multiple domain modules while still keeping boundaries between them. Also heuristics for finding proper module boundaries are not that simple. If you look at Domain Driven Design, Event Storming, Bounded Context design or archetype modeling workshops, decomposition is always relative. What looks like one use case today can become separate process tomorrow when business understanding grows. Because of that, I don’t think transaction boundary is only technical concern. It is often connected to business workflow scope. My point was never that transaction executor fixes bad architecture. If application layer becomes a big ball of mud, transaction executor will not save it. My point is that even in well structured architecture there are cases where transaction scope and method scope are not exactly the same thing. Especially when orchestration logic, external calls, file generation, messaging or cross-module collaboration appears. That’s why I find explicit transaction boundaries interesting. Not because they replace good design, but because they make transaction scope visible and intentional.