Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some clarification about Spring @Transactional annotation on a method

I am quite new in Spring world and I have developed a simple project that use Spring 3.2.1 and Hibernate 4.1.9 to implement a DAO. The project work correctly but I have some doubts about the use of @Transactional Spring annotation on CRUD method of this DAO.

This is the entire code of the class that implement the CRUD operation of my project:

package org.andrea.myexample.HibernateOnSpring.dao;  import java.util.List;  import org.andrea.myexample.HibernateOnSpring.entity.Person;  import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.springframework.transaction.annotation.Transactional;  public class PersonDAOImpl implements PersonDAO {      // Factory per la creazione delle sessioni di Hibernate:     private static SessionFactory sessionFactory;      // Metodo Setter per l'iniezione della dipendenza della SessionFactory:     public void setSessionFactory(SessionFactory sessionFactory) {         this.sessionFactory = sessionFactory;     }      /** CREATE CRUD Operation:      * Aggiunge un nuovo record rappresentato nella tabella rappresentato      * da un oggetto Person      */     @Transactional(readOnly = false)     public Integer addPerson(Person p) {          System.out.println("Inside addPerson()");          Session session = sessionFactory.openSession();          Transaction tx = null;         Integer personID = null;          try {             tx = session.beginTransaction();              personID = (Integer) session.save(p);             tx.commit();         } catch (HibernateException e) {             if (tx != null)                 tx.rollback();             e.printStackTrace();         } finally {             session.close();         }          return personID;      }      // READ CRUD Operation (legge un singolo record avente uno specifico id):     public Person getById(int id) {          System.out.println("Inside getById()");          Session session = sessionFactory.openSession();          Transaction tx = null;                   Person retrievedPerson = null;            try {             tx = session.beginTransaction();             retrievedPerson = (Person) session.get(Person.class, id);             tx.commit();         }catch (HibernateException e) {              if (tx != null)                                  tx.rollback();                       e.printStackTrace();         } finally {                              session.close();         }          return retrievedPerson;     }      // READ CRUD Operation (recupera la lista di tutti i record nella tabella):     @SuppressWarnings("unchecked")     public List<Person> getPersonsList() {          System.out.println("Inside getPersonsList()");          Session session = sessionFactory.openSession();         Transaction tx = null;         List<Person> personList = null;          try {             tx = session.beginTransaction();             Criteria criteria = session.createCriteria(Person.class);             personList = criteria.list();             System.out.println("personList: " + personList);             tx.commit();         }catch (HibernateException e) {              if (tx != null)                                  tx.rollback();                       e.printStackTrace();         } finally {             session.close();         }         return personList;     }      // DELETE CRUD Operation (elimina un singolo record avente uno specifico id):     public void delete(int id) {          System.out.println("Inside delete()");          Session session = sessionFactory.openSession();         Transaction tx = null;          try {             tx = session.beginTransaction();             Person personToDelete = getById(id);             session.delete(personToDelete);             tx.commit();         }catch (HibernateException e) {              if (tx != null)                                  tx.rollback();                       e.printStackTrace();         } finally {             session.close();         }      }      @Transactional     public void update(Person personToUpdate) {          System.out.println("Inside update()");          Session session = sessionFactory.openSession();         Transaction tx = null;          try {             System.out.println("Insite update() method try");             tx = session.beginTransaction();             session.update(personToUpdate);              tx.commit();         }catch (HibernateException e) {              if (tx != null)                                  tx.rollback();                       e.printStackTrace();         } finally {             session.close();         }         }  } 

Ok,as you can see some methods are annoted using @Transactional annotation.

I am readin the official documentation here http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html about the use of this annotation on methods and it see that: A method annoted using @Transactional must have transactional semantics but what it means with transactional semantics?

It means that the methos execution has to be considered as the execution of a transaction? So it means that the method operations have to be considered as a single operation that which may lead to a success or a failure, if successful, the results of operations has to be permanent, whereas in case of failure to return to the state prior to the start of the transaction.

Is this the meaning of use @Transactional annotation on a method?

And what exactly mean the readOnly = false attribute in the @Transactional annotation of the addPerson() method? it mean that I can also write a record in the database (and not only read it) or what? The doubt is related because I have understand that, by default, a transaction definied using @Transactional annotaion is read/write and not just read... I have also try to delete the (readOnly = false) attribute and still work well (insert the new record in the database table)

The following dout is: "why some method are annoted using @Transactional annotation and some other methods not? is it a good pratcice to annote ALL CRUD method withd @Transactional?"

Tnx

Andrea

like image 906
AndreaNobili Avatar asked Mar 08 '13 18:03

AndreaNobili


People also ask

What does @transactional annotation do in Spring?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.

What does @transactional annotation mean?

The @Transactional annotation is metadata that specifies that an interface, class, or method must have transactional semantics; for example, "start a brand new read-only transaction when this method is invoked, suspending any existing transaction".

What is the use of @transactional annotation in Java?

Transactional annotation provides the application the ability to declaratively control transaction boundaries on CDI managed beans, as well as classes defined as managed beans by the Java EE specification, at both the class and method level where method level annotations override those at the class level.

What happens if one @transactional annotated method is calling another @transactional annotated method on the same object instance?

1 Answer. Show activity on this post. If you call method2() from method1() within the same class, the @Transactional annotation of the second method will not have any effect because it is not called through proxy, but directly.


1 Answers

First of all, you shouldn't make DAO methods transactional, but service methods.

Second, using Transactional is a way to let Spring start and commit/rollback transactions for you. So you shouldn't start and commit transactions yourself.

Third: this will only work if you use a transaction manager that knows how to associate a Hibernate session with the transaction (typically, a HibernateTransactionManager). The session factory should also be handled by Spring, and injected by Spring in your DAOs. The code of the DAO should look like this:

Fourth: you should not open a new session, but get the current one, associated to the current transaction by Spring.

public class PersonDAOImpl implements PersonDAO {      @Autowired     private SessionFactory sessionFactory;      public Integer addPerson(Person p) {         Session session = sessionFactory.getCurrentSession();         Integer personID = (Integer) session.save(p);         return personID;     }      public Person getById(int id) {         Session session = sessionFactory.getCurrentSession();         Person retrievedPerson = (Person) session.get(Person.class, id);         return retrievedPerson;     }      @SuppressWarnings("unchecked")     public List<Person> getPersonsList() {         Session session = sessionFactory.getCurrentSession();         Criteria criteria = session.createCriteria(Person.class);         return criteria.list();     }      public void delete(int id) {         Session session = sessionFactory.getCurrentSession();         Person personToDelete = getById(id);         session.delete(personToDelete);     }      public void update(Person personToUpdate) {         Session session = sessionFactory.getCurrentSession();         session.update(personToUpdate);     } } 

Read the documentation for more information.

like image 84
JB Nizet Avatar answered Sep 26 '22 07:09

JB Nizet