【问题标题】:Spring Session Management Issue春季会话管理问题
【发布时间】:2013-02-11 16:45:39
【问题描述】:

我在我的演示应用程序中使用 Hibernate+Spring+Jsf 我希望 Spring 将处理事务管理所以我在 application-context.xml 文件中创建了这些条目..

    <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); 我强行通过异常,但数据仍保存在数据库中?如果出现异常,为什么不回滚数据,为什么不处理这种情况?

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

}

【问题讨论】:

    标签: spring hibernate jsf-2 spring-transactions


    【解决方案1】:

    似乎事务边界是 UserService 类上的每个方法。当您说userService.addUser(user) 时,这是一个事务的开始和完成。因此,当您说userService.deleteUser(null) 时,它是另一个事务——尽管它失败了,但前一个事务并没有回滚,因为它已经被提交了。

    如果您想在一个事务中完成所有操作,请使用 @Transactional 注释您的 addUser()(或包含在程序化事务中)

    【讨论】:

    • 程序化交易是什么意思?
    • 声明性事务边界是当您使用 @Transactional 注释您的方法时。程序化事务边界是当你调用类似session.beginTransaction() 的时候。我在您的最后一个代码 sn-p 上指的是public String addUser(),它没有@Transactional 注释
    • 是的,我只在类级别删除和添加,但现在即使我没有强行抛出异常,但现在数据没有保存在数据库中
    • 您使用的是什么持久性技术。如果您使用的是 JPA/Hibernate,请确保在最后刷新,以便传播更改。
    • 我正在使用 Hibernate,我必须在哪里添加 FLush?我已经添加了有问题的 DAO 类
    【解决方案2】:

    方法上的@Transactional 注释定义了事务的边界(除非其他人已经在运行“外部事务”)。以同样的方式,该类的@Transactional 注释使对该类实例的(公共)方法的所有单个调用都具有事务性,但使连续 方法调用被包装在单个事务中的同一实例。相反,每个方法调用都在其自己的事务中运行,如果方法正常返回,则提交事务。 (默认情况下,如果抛出已检查的异常,它甚至会被提交,尽管您可以使用 rollbackFornoRollbackFor 参数更改它。)

    所以在您的情况下,您有两个交易;一个用于此调用:

    userService.addUser(user);
    

    成功创建用户并在对addUser 的调用完成时提交,第二个:

    userService.deleteUser(null);
    

    当 NullPointerException 从方法调用中引发时回滚。 (我猜你在这里得到了一个 NPE,因为这是 RuntimeExcepotion 的子类,它会导致回滚。)

    如果您想在单个事务中包含两个语句,则需要将事务置于更高级别。这里的 '@Transactional` 注释不会有什么坏处,但它们不是你想要的。

    【讨论】:

    • @Transactional 只是使该类的所有公共方法具有事务性的简写。它不会使“整个班级”成为事务性的。
    • 你能告诉我我们如何使用事务管理,以便在异常出现时回滚数据
    • 好吧,例如,在您的情况下,您可以将包含 IUserService userService 的类上的addUser() 方法标记为@Transactional,然后应该回滚事务当异常在addUser() 方法之外传播时 - 假设当它作为接口通过spring 注入时它是从另一个类中调用的。但是,不要在 addUser() 类上捕获 DataAccessException,而是在调用它的那个类上。
    猜你喜欢
    • 1970-01-01
    • 2012-08-10
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多