Transactions
Which operations belong in one atomic unit, why a network call inside a transaction is a resource problem, and what to do when a commit and a message must both happen.
BEGIN, COMMIT and ROLLBACK as things your code controls: bound to one connection, ended by an error you did not expect, and retried when the database says so.
Which operations must commit together, which merely happen nearby, and why "the whole handler" is almost never the right answer.
Splitting a unit of work trades an atomicity guarantee for shorter locks — and buys you an intermediate state you now have to design.
A five-second payment call between BEGIN and COMMIT holds a pooled connection and every lock the transaction took, for five seconds, on every request.
The commit succeeds and the publish fails, or the publish succeeds and the commit rolls back. Two systems, no shared transaction, and no ordering that fixes it.
Write the event as a row in the same transaction as the state change, then publish it from a background reader — at-least-once, by design.
Two transactions take the same two locks in opposite orders, each waits for the other, and the database kills one of them — with an error your code has to expect.