What is the purpose of the @Transactional(readonly = false) annotation?

Asked

Viewed 5,362 times

2

Annotation used for service injection in the Spring Framework.

1 answer

4


The concept of transaction in Spring can be described with the acronym ACID below:

Atomicity: The transaction must be treated as a single operation, which means that all commands present in this transaction can be completed successfully or without success. Nothing will be saved if at least 1 command of 100 goes wrong, all must run successfully, no errors.

Consistency: This represents the integrity consistency of the database, they are: unique primary keys and etc.

Isolation: Many transaction can be executed at the same time, isolation ensures that each transaction is isolated from the other, preventing data corruption.

Durability: A transaction after persistence must remain persisted and cannot be deleted for system failures. Once you understand the concept, you should also keep in mind that there are 2 ways to work with transactions in an application: Programmatically or Declaratively.

Working programmatically brings immense flexibility to manage your transactions, but the maintainability of the code becomes difficult and costly. On the other hand, working Declaratively is more elegant and follows good programming practices, as you will be totally separating transaction control from business rules. When it comes to Spring Framework you can work declaratively through XML or Annotations, but in this article we will focus on annotations.

Transactions with Spring Framework

Before you start using transactions you need to tell Spring that you want to control transactions via annotations, this is done through cofinguration shown in list 1 in the applicationContext.xml file.

Listing 1: Enabling transactions via annotations in the applicationContext.xml

<tx:annotation-driven transaction-manager="transactionManager"/>

After that you will be able to use the @Transactional annotation in order to define which method should be within a transaction.

Isolation The first parameter found is Isolation, this can be defined as follows:

Listing 2: Defining Insulation Level / Isolation Level

@Transactional(Isolation = Isolation.READ_COMMITTED) Possible types for Isolation are:

  • ISOLATION_DEFAULT: Standard insulation level.
  • ISOLATION_READ_COMMITTED: Prevents only "Dirty reads".
  • ISOLATION_READ_UNCOMMITED: Indicates that "Dirty reads", "non-repeatable reads" and "phatom reads" may occur, meaning they will not be prevented.
  • ISOLATION_REPEATABLE_READ: Prevents only "Dirty reads" and "non-repeatable reads".
  • ISOLATION_SERIALIZABLE: Prevent "Dirty reads", "non-repeatable reads" and "phatom reads".

Our focus is not to teach in depth the operation of transactions, only their application to Spring, but we will briefly explain these types of preventable readings in Isolation.

Dirty Read: occurs when a transaction A writes an X value and a transaction B reads this X value without the transaction A having committed or rollback the transaction. If transaction A of a rollback, the value that transaction B read becomes invalid.

Non-repeatable read: Occurs when in the same transaction a line is read twice and the values of these two readings are different.

Phatom Read: Occurs when two identical querys are executed and the result of the second is different from the first.

Defining Propagation / Propagation

Another very important parameter to be defined in a Spring transaction is how the propagation of that transaction will be performed. See below the possible forms of propagation:

PROPAGATION_MANDATORY: Requires the use of a transaction, if there is no current transaction, an exception is made.

PROPAGATION_NESTED: Executes within a nested transaction if a current transaction exists.

PROPAGATION_NEVER: Prevents the use of a transaction. If there is a current transaction, an exception is made.

PROPAGATION_NOT_SUPPORTED: Does not use the current transaction. It is always executed without any transaction.

PROPAGATION_REQUIRED: Uses the current transaction if it exists, if it does not exist creates a new transaction.

PROPAGATION_REQUIRES_NEW: Create a new transaction, if a current already exists, suspend it.

PROPAGATION_SUPPORTS: Uses the current transaction if it exists, otherwise executes without transaction.

There is still the parameter "readonly" in the annotation @Transactional. This specifies that no DML operation can be performed (Insert, Delete or Update), ie only queries.

In list 3 defined a class that uses Spring transaction control, this one will use a readonly=false and a PROPAGATION_REQUIRED, so we ensure that always the save method will be executed within a transaction.

Listing 3: Using @Transactional in practice

@Repository
public class ProductDAOImpl implements ProductDAO { 
    private SessionFactory sessionFactory;

    @Autowired 
    public ProductDAOImpl(SessionFactory sessionFactory) { 
        this.sessionFactory = sessionFactory; 
    }

    private Session currentSession(){ 
    return sessionFactory.getCurrentSession(); 
    }

    @Override  //para execução deste método é requerido uma 
              //transação, é isso que estamos dizendo aqui 
    @Transactional(propagation=Propagation.REQUIRED,readOnly=false) 
    public void save(ProductTech product) { 
        currentSession().save(product); 
        System.out.println(“product saved with sucess”); 
    } 
}

Other annotations like @Autowired and @Repository are Spring definitions as well, which will not be focused on this article. As you can see in the method "save" defined the transaction as PROPAGATION_REQUIRED, so if we had 10 birds inside save, all should necessarily succeed in its execution, otherwise a rollback would be performed.

Source: http://www.devmedia.com.br/spring-framework-controle-de-transacoes-usando-anotacoes/28916

Browser other questions tagged

You are not signed in. Login or sign up in order to post.