Every time you execute a SQL statement in JDBC, by default JDBC provides a transaction. However most of the time this default behavior is not sufficient and it is your responsibility to define the transactional boundaries.
The default behavior, where each statement is contained within its own transaction, is controlled by the connection's autocommit mode. When autocommit is enabled, each change is committed to the database automatically. When you disable autocommit, you become responsible for defining the start and end of a transaction which lets you determine whether to commit or rollback the entire transaction. To disable a connection's auto-commit mode, call the setAutoCommit() method, which accepts a single Boolean parameter.
When you call commit(), the current transaction ends and, if possible, all changes made prior to the call are saved. However, if the database is unable to save any one of the changes, then none of them are saved.
You can wrap the execution inside a try-catch block and call rollback on the connection whenever an exception happens:
These are just simple cases. When you are dealing with mutiple users trying to access the database at the same time (most real world scenarios) you have to consider lot of other transaction isolation levels.
EJBs is not the only way to implement transactions. Even Spring framework supports transactions.