2013-02-11 2 views
0

Я использую Hibernate + Spring + JSF в моем демонстрационном приложении я хочу Spring будет Генделем управления транзакциями Так я сделал эти записи в приложении-context.xml файл ..Управления сеансов Spring Issue

<beans xmlns="http://www.springframework.org/schema/beans" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:tx="http://www.springframework.org/schema/tx" 
      xmlns:context="http://www.springframework.org/schema/context" 
      xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 

     <!-- Beans Declaration --> 
     <bean id="User" class="com.otv.model.User"/> 

     <!-- User Service Declaration --> 
     <bean id="UserService" class="com.otv.user.service.UserService"> 
      <property name="userDAO" ref="UserDAO" /> 
     </bean> 

     <!-- User DAO Declaration --> 
     <bean id="UserDAO" class="com.otv.user.dao.UserDAO"> 
      <property name="sessionFactory" ref="SessionFactory" /> 
     </bean> 

     <!-- Data Source Declaration --> 
     <bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
      <property name="driverClass" value="org.postgresql.Driver" /> 
      <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/postgres" /> 
      <property name="user" value="postgres" /> 
      <property name="password" value="hariom" /> 
      <property name="maxPoolSize" value="10" /> 
      <property name="maxStatements" value="0" /> 
      <property name="minPoolSize" value="5" /> 
     </bean> 

     <!-- Session Factory Declaration --> 
     <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
      <property name="dataSource" ref="DataSource" /> 
      <property name="annotatedClasses"> 
       <list> 
        <value>com.otv.model.User</value> 
       </list> 
      </property> 
      <property name="hibernateProperties"> 
       <props> 
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
        <prop key="hibernate.show_sql">true</prop> 
<prop key="hibernate.connection.autocommit">false</prop> 
       </props> 
      </property> 
     </bean> 

     <!-- Enable the configuration of transactional behavior based on annotations --> 
     <tx:annotation-driven transaction-manager="txManager"/> 

     <!-- Transaction Manager is defined --> 
     <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
      <property name="sessionFactory" ref="SessionFactory"/> 
     </bean> 

    </beans> 

И UserService .java класс

package com.otv.user.service; 

import java.util.List; 

import org.springframework.transaction.annotation.Transactional; 

import com.otv.model.User; 
import com.otv.user.dao.IUserDAO; 

/** 
* 
* User Service 
* 
* @author onlinetechvision.com 
* @since 25 Mar 2012 
* @version 1.0.0 
* 
*/ 
@Transactional(readOnly = true) 
public class UserService implements IUserService { 

    // UserDAO is injected... 
    IUserDAO userDAO; 

    /** 
    * Add User 
    * 
    * @param User user 
    */ 
    @Transactional(readOnly = false) 
    public void addUser(User user) { 
     getUserDAO().addUser(user); 
    } 

    /** 
    * Delete User 
    * 
    * @param User user 
    */ 
    @Transactional(readOnly = false) 
    public void deleteUser(User user) { 
     getUserDAO().deleteUser(user); 
    } 

    /** 
    * Update User 
    * 
    * @param User user 
    */ 
    @Transactional(readOnly = false) 
    public void updateUser(User user) { 
     getUserDAO().updateUser(user); 
    } 

    /** 
    * Get User 
    * 
    * @param int User Id 
    */ 
    public User getUserById(int id) { 
     return getUserDAO().getUserById(id); 
    } 

    /** 
    * Get User List 
    * 
    */ 
    public List<User> getUsers() { 
     return getUserDAO().getUsers(); 
    } 

    /** 
    * Get User DAO 
    * 
    * @return IUserDAO - User DAO 
    */ 
    public IUserDAO getUserDAO() { 
     return userDAO; 
    } 

    /** 
    * Set User DAO 
    * 
    * @param IUserDAO - User DAO 
    */ 
    public void setUserDAO(IUserDAO userDAO) { 
     this.userDAO = userDAO; 
    } 

} 

Теперь я мой боб я делаю

@ManagedProperty(value="#{UserService}") 
    IUserService userService; 

    */ 
    public IUserService getUserService() { 
     return userService; 
    } 

    /** 
    * Set User Service 
    * 
    * @param IUserService - User Service 
    */ 
    public void setUserService(IUserService userService) { 
     this.userService = userService; 
    } 

    public String addUser() { 
     try { 
      User user = new User(); 
      user.setId(getId()); 
      user.setName(getName()); 
      user.setSurname(getSurname()); 
      userService = getUserService(); 
      userService.addUser(user); 
      userService.deleteUser(null); 
      return SUCCESS; 
     } catch (DataAccessException e) { 
      e.printStackTrace(); 
     } 

     return ERROR; 
    } 

Вот в этом коде userService.deleteUser(null); Я могу устранить исключение, но все же данные сохраняются в базе данных? Почему менеджмент Trasaction не справляется с этой ситуацией, если возникает исключение, почему он не откатывает данные?

UserDAO Класс

package com.otv.user.dao; 

import java.util.List; 

import com.otv.model.User; 

import org.hibernate.SessionFactory; 


public class UserDAO implements IUserDAO { 

    private SessionFactory sessionFactory; 

    /** 
    * Get Hibernate Session Factory 
    * 
    * @return SessionFactory - Hibernate Session Factory 
    */ 
    public SessionFactory getSessionFactory() { 
     return sessionFactory; 
    } 

    /** 
    * Set Hibernate Session Factory 
    * 
    * @param SessionFactory - Hibernate Session Factory 
    */ 
    public void setSessionFactory(SessionFactory sessionFactory) { 
     this.sessionFactory = sessionFactory; 
    } 

    /** 
    * Add User 
    * 
    * @param User user 
    */ 
    public void addUser(User user) { 
     getSessionFactory().getCurrentSession().save(user); 
    } 

    /** 
    * Delete User 
    * 
    * @param User user 
    */ 
    public void deleteUser(User user) { 
     getSessionFactory().getCurrentSession().delete(user); 
    } 

    /** 
    * Update User 
    * 
    * @param User user 
    */ 
    public void updateUser(User user) { 
     getSessionFactory().getCurrentSession().update(user); 
    } 

    /** 
    * Get User 
    * 
    * @param int User Id 
    * @return User 
    */ 
    public User getUserById(int id) { 
     List list = getSessionFactory().getCurrentSession() 
              .createQuery("from User where id=?") 
              .setParameter(0, id).list(); 
     return (User)list.get(0); 
    } 

    /** 
    * Get User List 
    * 
    * @return List - User list 
    */ 
    public List<User> getUsers() { 
     List list = getSessionFactory().getCurrentSession().createQuery("from User").list(); 
     return list; 
    } 

} 

ответ

2

Кажется границы транзакций каждый метод в классе UserService. Когда вы говорите userService.addUser(user), это одна транзакция началась и закончилась. Следовательно, когда вы говорите userService.deleteUser(null), это еще одна транзакция - и, хотя она терпит неудачу, предыдущая не откат, потому что она уже завершена.

Если вы хотите сделать все в одной транзакции, аннотировать AddUser() с @Transactional (или вложить в программной операции)

+0

Что вы подразумеваете под программную транзакцию? –

+0

И adduser уже имеет @Transactional (readOnly = false) –

+0

Декларативная граница транзакции - это когда вы комментируете свой метод с помощью @Transactional. Программная граница транзакции - это когда вы вызываете нечто вроде 'session.beginTransaction()'.Я имел в виду 'public String addUser()' в вашем последнем фрагменте кода, который не имеет @Transactional аннотации – gerrytan

1

@Transactional аннотацию на методе не определяет границу сделки (если кто-то другой уже работает «внешняя транзакция»). В том же образом @Transactional аннотировании класса делает все одиночных вызовов к (общественным) методам экземпляров этого класса транзакционного, но делает не сделать последовательных методы вызывают тот же экземпляр завернутыми в одной транзакции , Вместо этого каждый вызов метода выполняется в своей собственной транзакции, и транзакция выполняется, если метод возвращается нормально. (По умолчанию он даже совершается, если выбранное исключение выбрано, хотя вы можете изменить его с помощью параметров rollbackFor и noRollbackFor.)

Так что в вашем случае у вас есть две сделки; один для этого вызова:

userService.addUser(user); 

успешно создает пользователя и совершается, когда вызов addUser закончен, а второй один:

userService.deleteUser(null); 

, который откатывается когда NullPointerException возникает из вызов метода. (Я предполагаю, что здесь вы получаете NPE, и поскольку это подкласс RuntimeExcepotion, он вызывает откат.)

Если вы хотите иметь оба оператора в одной транзакции, вам необходимо иметь транзакцию на более высоком уровне. Аннотации '@ Transactional` здесь не повредят, но они не то, что вы хотите.

+0

Я уже определил @Transactional в классе уровня –

+0

'@ Transactional' является лишь сокращением, чтобы сделать все общедоступные методы этого класса транзакционными. Он умирает, не делает «весь класс» транзакционным. –

+0

Не могли бы вы дать мне знать, как мы можем использовать управление trasaction так, чтобы в случае исключения возникла его roolback данные –