It's a delegate discussion: using exceptions instead of error codes. LLBLGen Pro throws exceptions where it can't continue and what's in progress has to stop. That's basicly what's the rule of thumb we use to decide whether an exception should be thrown or not.
Now, you can stop logic with a return value as well, simply test on the return value, and if it's an error, stop your routine. However, that doesn't really work well in a system where a lot of objects take part in a process which takes multiple steps. In such a system, you simply want to have an exception so the execution ends up in a handler from which you can recover or give up.
The validation logic for example throws an exception because the value will otherwise always result in an exception later on, plus (and this is the main part) databinding code often only refuses to proceed if an exception occured.
With transactions, there's really no other way to stop them than to throw an exception, as otherwise you'll end up in return value hell, where you have to report upwards return values like what's done in COM which can get out of hand because you might want to add more info than just 'it failed', like which entity failed and where.
In these situations, an exception is a great thing to have because you simply throw it and the RESPONSIBLE routine will get it as the responsible routine was the one calling the throwing code (indirectly) anyway.
At that level, the routine should determine to give up or retry/recover.
However, as walaa said, try to avoid exceptions up front, by validation. This means that when a save action is started, you already know the data is correct to a level where you could test it to be correct (it might give up because it clashes with a unique constraint for example but that was out of your control at that point).