Existem várias aplicações práticas, mas uma que eu gosto muito é quando você está trabalhamdo com threads e podemos pensar em uma entidade para os trabalhos jobs
que é populada por tarefas longas a serem executadas no background.
Num cenário hipotético, se você tiver 64 threads rodando em paralelo precisa de alguma forma garantir que não haverá uma race condition - por exemplo: dois ou mais processos pegarem um job e iniciarem a mesma tarefa.
Nesse caso você pode iniciar uma transaction, e fazer um "SELECT FOR UPDATE" na entidade jobs
que irá receber um lock até que essa transaction seja resolvida com um COMMIT ou um ROLLBACK. Isso garante que a thread/worker que pegou aquela tarefa faça o UPDATE na entidade atribuindo um PID
e finalmente te dá uma forma de um outro processo como watchdog monitorar se o PID ainda está em execução e todo processo dos threads correr de forma organizada.
Mas além dessa aplicação existem várias outras aonde, por exemplo, você tenha regra de negócio entre a Primary Key a Foreign Key e deseje fazer um rollback para não deixar uma entidade orders
sem itens
(um case bastante comum).
E de maneira bastante ampla existem várias aplicações, mas a regra é simples: se precisou de uma entidade atômica, então requer de uma transaction. Mas se ainda não ficou claro, posso dar outro último exemplo: imagine que seu sistema utilize Redis + Mongo + Postgres ou MySQL (comum em microsserviços), e uma entidade para ser salva no MySQL depende do Redis e do Mongo, você utiliza uma transaction para validar tudo e após inserir corretamente, você COMMITA a transação, se não faz rollback.
Espero ter ficado claro.