SQL Server can unilaterally decide to rollback your transaction. This is a severe design flaw in SQL Server because your app can never know whether the transaction is still active or not. It is not well documented what kinds of errors roll back and what kinds of errors don't. For example, I think I remember that unique key violations and other data errors do not roll back. But others do. Some errors even terminate the connection (that is rare and not a design flaw).
I recommend that you code in such a way that you abort the transaction at the first error and then either fail or retry everything. That saves you a lot of headaches. Prefer to execute one statement per batch, or you risk running the 2nd statement outside of a transaction.
If you really want to keep going after errors you must do two things:
- Build a whitelist of errors that do not roll back. In that case you can keep going.
- Check with
SELECT @@TRANCOUNT
whether the transaction is still live.