4.1 Introduction to transactions in Hibernate

To all of the above, I would like to add information about transactions. As you already know, a transaction is a group of actions that must be performed only all together . If any action failed or was executed with an error, then all other actions must be canceled.

Hibernate is able to work with two types of transactions:

  • JDBC
  • JTA

A JDBC transaction is actually a database transaction. It is tied to working with the database, to the JDBC connection. And he makes sure that the actions when working with the database are performed as they should: either all or nothing.

JTA - Transaction is an application level transaction. It is not tied to any database. Its task is to ensure that certain actions are performed: either all or nothing.

For example, you can write data to several different databases within a single JTA transaction. Then if an error occurs, then the JTA transaction will have to roll back the changes in all databases. Even those that were executed successfully in terms of a particular database.

4.2 Hibernate Transactions Interface

In the Hibernate library, a transaction is represented by the Transaction interface, which can have different implementations. For example, when working with Spring, Spring provides its own JTA transaction mechanism.

The methods of this interface are:

# Method Description
1 begin() Starts a new transaction
2 commit() Ends transaction, pushes/commits all changes
3 rollback() Rolls back the current transaction
4 setTimeout(int seconds) Sets the maximum transaction execution time
5 isActive() Checks if a transaction is active or not
6 wasRolledBack() Checks if the transaction rolled back normally
7 wasCommitted() Checks if the transaction has committed normally
8 registerSynchronization() Registers a callback to control the transaction

Important! Creating a transaction object and starting a transaction are two different things. Here you can draw an analogy with the Thread class. When you create a Thread() object, the JVM doesn't start a new thread yet. To start it, you need to call the start() method on the Thread object. It's the same with a transaction - it needs to call the begin() method.

An example of how transactions are usually handled in Hibernate:


Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
try {
    transaction.begin();
    Long count = session.createQuery("select count(*) from Employee", Long.class).uniqueResult();
    transaction.commit();
}
catch (Exception e) {
	if (transaction.getStatus() == ACTIVE || transaction.getStatus() == MARKED_ROLLBACK) {
    transaction.rollback();
    }
}
finally {
	session.close();
	sessionFactory.close();
}

We see three things here:

First, all work with the database is wrapped in a transaction by calling methods begin()and commit()All actions between calls to these two methods must be performed: either all together, or nothing.

Secondly, if any error occurs, we try to rollback the transaction - call the rollback(). This means that TransactionManger must first record all the actions that were between begin()and commit(), and then return everything as it was if we called rollback().

And by the way, it's not a fact that there will be no error when calling the rollback method. Mistakes always happen. You just need to accept this fact and be ready for it.

4.3 Transaction manager

From a transaction management perspective, Hibernate is just a lightweight object wrapper for JDBC. Hibernate itself does not have transaction processing features. Hibernate Transaction is actually a wrapper for the underlying JDBC transaction (or JTA transaction wrapper). JDBCTransaction is the default. Example from Hiberante settings file:


hibernate.transaction.factory_class  org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.factory_class  org.hibernate.transaction.JDBCTransactionFactory

Let's take another look at our code using transactions:


Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
//here is your code for working with the base
session.flush();
transaction.commit();
session.close();

Now let's look at the JDBCTransaction class code:


public class JDBCTransaction implements Transaction {
 
    public void begin() throws HibernateException {
    	...
    	if (toggleAutoCommit) jdbcContext.connection().setAutoCommit(false);
    	...
    }
}

This is the method to start a transaction. Then look at the send method:


public void commit() throws HibernateException {
    ...
    jdbcContext.connection().commit();
    ...
    jdbcContext.connection().setAutoCommit( true );
    ...
}

Now let's substitute this code into the Hibernate example code:

Hibernate Simple JDBC Code

Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
//here is your code for working with the database
session.flush();
transaction.commit();
session.close();

Connection conn = jdbcContext.connection();
conn.setAutoCommit(false);
 
//here is your database code
conn.commit ()
conn.setAutoCommit(true);
conn.close();

So native Hibernate transactions are just native JDBC calls to the database. Nothing more and nothing less. But JTA transactions are more interesting. But more about that another time.

undefined
1
Task
Module 4. Working with databases, level 16, lesson 3
Locked
Transactions
task1605