You would need to throw an unchecked Exception that bubbles across the transaction boundary - IOException is not unchecked, hence no rollback,
IOException