Start here. This is the direct spoken answer to practice first.
Overview
A transaction should protect one database consistency decision, not an arbitrary layer or an entire request by default.
I usually place the transaction on an application-service method that performs one use case, such as reserving inventory and recording the order. Repositories participate in that transaction rather than each defining an unrelated commit. The boundary should be long enough to protect the invariant and short enough to release the connection and locks promptly. Validation that does not require locked database state can happen before it.