2013-03-08 3 views
29

Я совершенно новый в весеннем мире, и я разработал простой проект, который использует Spring 3.2.1 и Hibernate 4.1.9 для реализации DAO. Проект работает правильно, но у меня есть некоторые сомнения относительно использования @Transactional Весенняя аннотация по CRUD-методу этого DAO.Некоторые пояснения к примечанию Spring @Transactional по методу

Это весь код класса, которые реализуют операцию CRUD моего проекта:

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(); 
     } 

    } 

} 

Хорошо, как вы можете видеть, что некоторые методы annoted с помощью @Transactional аннотации.

Я читаю официальную документацию здесь http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html об использовании этой аннотации методов и видеть, что: метода annoted с использованием @Transactional должна транзакционная семантикой но что это означает транзакционную семантику?

Это означает, что выполнение methos должно рассматриваться как исполнение транзакции? Таким образом, это означает, что операции метода должны рассматриваться как одна операция, которая может привести к успеху или неудаче, если результаты успешны, результаты операций должны быть постоянными, тогда как в случае отказа вернуться в состояние до начало транзакции.

Это смысл использования @Transactional аннотация по методу?

А что именно означает ReadOnly = ложный атрибут в @Transactional аннотирования addPerson() метод? это значит, что я могу написать запись в базе данных (и не только прочитать ее), или что? Уверенность связана с тем, что я понимаю, что по умолчанию транзакция, определенная с использованием @Transactional annotaion, составляет . Чтение/запись и не просто чтение ... Я также попытался удалить атрибут (readOnly = false) и все еще хорошо работают (вставьте новую запись в таблицу базы данных)

Следующий dout: «почему какой-то метод аннотируется с помощью аннотации @Transactional, а некоторые другие методы нет? Это хорошая оценка, чтобы аннотировать метод ALL CRUD, транзакционный?»

Tnx

Andrea

+0

Я предполагаю, что ваша конфигурация транзакции недействительна, поскольку вы можете вставить что-то с транзакцией только для чтения. Я предполагаю, что вы вообще не используете транзакции. Пожалуйста, дайте нам более подробную информацию о том, как вы настроили среду транзакций (appcontext). Также не объявляйте свои транзакции на уровне DAO, а на уровне бизнеса (там, где вы фактически используете DAO). –

ответ

51

Прежде всего, вы не должны делать DAO методы транзакционных, но методы обслуживания.

Во-вторых, использование Transactional - это способ разрешить вам запуск Spring и commit/rollback. Поэтому вы не должны начинать и совершать транзакции самостоятельно.

В-третьих: это будет работать, если вы используете диспетчер транзакций, который знает, как связать сеанс Hibernate с транзакцией (как правило, HibernateTransactionManager). Сессионный завод также должен обрабатываться весной и вводиться весной в ваши DAO. Код DAO должен выглядеть так:

В-четвертых: вы не должны открывать новый сеанс, а получать текущий, связанный с текущей транзакцией по весне.

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); 
    } 
} 

Прочитать the documentation для получения дополнительной информации.

+1

Хорошо ... теперь у меня больше сомнений, чем перед отправкой моего вопроса :-) 1) Что значит, что я не должен делать методы DAO транзакционными, но сервисными методами? Я нашел много примеров, где метод DAO аннотируется с помощью аннотации @Transaction 2) Почему вы удалили эту аннотацию из метода, опубликованного в вашем ответе 3) Чтение здесь: http://www.tutorialspoint.com/ hibernate/hibernate_sessions.htm он говорит, что: «Объект Session является легким и предназначен для создания экземпляра каждый раз, когда требуется взаимодействие с базой данных» – AndreaNobili

+0

, а также: «Объекты сеанса не должны оставаться открытыми в течение длительного времени, потому что они обычно не должны быть потокобезопасными, и они должны быть созданы и уничтожены по мере необходимости ». Итак, что вы говорите мне, что это хорошая оценка, открыть сеанс только один раз, а затем получить текущую открытую сессию? – AndreaNobili

+9

Я не говорю этого. Я говорю, что вы должны получить сеанс, связанный с текущей транзакцией весной, и это также будет закрыто к весне в конце транзакции. Это Spring, который будет открывать и закрывать сеанс каждый раз, когда транзакция будет открыта/закрыта. То, что я имею в виду с помощью методов service vs DAO, заключается в том, что служба, как правило, вызывает несколько методов DAO, и все эти вызовы должны быть частью одного и того же trnsaction (например: уменьшение баланса учетной записи, увеличение баланса другой учетной записи, создание передайте объект, создайте aline в таблице аудита. –

Смежные вопросы