java - 如何为每个请求使用一个事务 Spring + Hibernate + Spring Security + JSF

标签 java spring hibernate jsf-2 spring-security

我正在使用 JSF 2.1 + Hibernate 4.1.7 + Spring 3.2.1 + Spring Security + SQLServer2012 开发 Web 应用程序。 一切正常,即 CRUD 操作。但有些方法需要使用 2 个或更多实体(例如更新、添加等)

getEntity1Service().merge();  // line 1
getEntity2Service().create(); // line 2
getEntity3Service().delete(); // line 3

如果执行第 2 行(创建实体)时发生错误,我需要合并实体(或更新、创建)或之前的数据库函数进行回滚,以便数据库上的数据保持正确

我将 OpenSessionInViewFilter@Transactional Spring 注释结合使用。

<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
    <init-param>
        <param-name>sessionFactoryBeanName</param-name>
        <param-value>SessionFactory</param-value>
    </init-param>
</filter>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

在我的GenericDAO中我有

getSessionFactory().getCurrentSession().merge(objeto);
getSessionFactory().getCurrentSession().delete(objeto);
getSessionFactory().getCurrentSession().createQuery(queryString);

我缺少什么?因为当执行第 #1 行时,数据被发送到 DB。

摘 self 的应用程序日志

执行第 1 行时

...
23 05 2013 00:04:46,650 DEBUG [http-apr-8080-exec-345] (e.engine.transaction.internal.jdbc.JdbcTransaction:doCommit:113) - committed JDBC Connection
23 05 2013 00:04:46,650 DEBUG [http-apr-8080-exec-345] (e.engine.transaction.internal.jdbc.JdbcTransaction:releaseManagedConnection:126) - re-enabling autocommit
23 05 2013 00:04:46,651 DEBUG [http-apr-8080-exec-345]
...

执行第 2 行时

(ork.orm.hibernate4.support.OpenSessionInViewFilter:lookupSessionFactory:188) - Using SessionFactory 'SessionFactory' for OpenSessionInViewFilter 23 05 2013 00:05:27,777 DEBUG [http-apr-8080-exec-349]
(ramework.beans.factory.support.AbstractBeanFactory:doGetBean:246) - Returning cached instance of singleton bean 'SessionFactory' 23 05 2013 00:05:27,777 DEBUG [http-apr-8080-exec-349]
(ork.orm.hibernate4.support.OpenSessionInViewFilter:doFilterInternal:141) - Opening Hibernate Session in OpenSessionInViewFilter 23 05 2013 00:05:27,778 DEBUG [http-apr-8080-exec-349]
(org.hibernate.internal.SessionImpl ::312) - Opened session at timestamp: 13692891277

提前谢谢您。

**感谢您的回复,已更新问题: ****

这是我的 applicationContext.xml:

<bean id="entity1DAO" class="com.x.dao.generic.GenericDAOHibernateImpl">
    <constructor-arg><value>com.x.entities.modules.general.Entity1</value></constructor-arg>
    <property name="sessionFactory"><ref bean="SessionFactory"/></property>
</bean>
<bean id="entity2DAO" class="com.x.dao.generic.GenericDAOHibernateImpl">
        <constructor-arg><value>com.x.entities.modules.general.Entity2</value></constructor-arg>
        <property name="sessionFactory"><ref bean="SessionFactory"/></property>
    </bean>
<bean id="entity3DAO" class="com.x.dao.generic.GenericDAOHibernateImpl">
        <constructor-arg><value>com.x.entities.modules.general.Entity3</value></constructor-arg>
        <property name="sessionFactory"><ref bean="SessionFactory"/></property>
    </bean>

<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
    <property name="jdbcUrl" value="jdbc:sqlserver://127.0.0.1:1433;databaseName=db1;user=sa;password=abcde1234" />
    <property name="maxPoolSize" value="10" />
    <property name="maxStatements" value="0" />
    <property name="minPoolSize" value="5" />
</bean>

<bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="DataSource" />
    <property name="annotatedClasses">
        <list>
            <value>com.x.entities.modules.configuration.cg.CgEntity1</value>
            <value>com.x.entities.modules.configuration.cg.CgEntity2</value>
            <value>com.x.entities.modules.configuration.cg.CgEntity3</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">com.x.dao.SqlServer2008Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.id.new_generator_mappings">true</prop>
            <prop key="hibernate.format_sql">false</prop>
            <prop key="use_sql_comments">true</prop>
        </props>
    </property>
</bean>

<!--Tells Spring framework to read @Transactional annotation-->
<context:annotation-config/> 
 <!-- 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>

我的数据访问层:GenericDAOHibernateImpl.java:

@Transactional(rollbackFor=Exception.class)
public class GenericDAOHibernateImpl <T, PK extends Serializable> implements GenericDAOHibernate<T, PK>, Serializable{

    @Override
    public void mergeEntity(T object) {
        getSessionFactory().getCurrentSession().merge(object);
    }

    @Override
    public void deleteEntity(T object) {
        getSessionFactory().getCurrentSession().delete(object);
    }
}

我的业务逻辑层> BeanJSF1.java (@ManagedBean):

//Injection to my generic dao:
    @ManagedProperty(value = "#{entity1DAO}")
    GenericDAOHibernate<Entity1,Integer> entity1Service;
    @ManagedProperty(value = "#{entity2DAO}")
    GenericDAOHibernate<Entity2,Integer> entity2Service;
    @ManagedProperty(value = "#{entity3DAO}")
    GenericDAOHibernate<Entity3,Integer> entity3Service;
    //other variables and methods 
    @Transactional(rollbackFor = Exception.class)
    public void onUpdatingRowData(RowEditEvent ree) {
        try{
            getEntity1Service().mergeEntity(ree.getObject());//this get committed on DB
            getEntity2Service().deleteEntity(object2);//this fires an Exception
        } catch (Exception ex) {
            Logger.getLogger(BeanJSF1.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

我尝试仅在我的GenericDAOHibernateImpl中使用@Transactional,GenericDAOHibernateImpl和Bussines Layer类都使用@Transactional,但我始终得到相同的结果

*第三个问题更新***

好的,我已经添加了服务层

DAO 层:

public interface IGenericDAOHibernate <T, PK extends Serializable>{ ...

public class GenericDAOHibernate <T, PK extends Serializable> implements IGenericDAOHibernate<T, PK>, Serializable{ ...

服务层:

public interface IGenericDAOHibernateService <T, PK extends Serializable>{ ...

@Transactional(rollbackFor = Exception.class)
public class GenericDAOHibernateImpl <T, PK extends Serializable> implements IGenericDAOHibernateService<T,PK>{
    public IGenericDAOHibernate genericDAOHibernate; ...

ApplicationContext.xml:

<bean id="GenericDAOService" class="com.x.services.generic.GenericDAOHibernateImpl"><property name="genericDAOHibernate" ref="GenericDAOHibernate" /></bean> 
 <bean id="GenericDAOHibernate" class="com.x.dao.generic.GenericDAOHibernate">
     <property name="sessionFactory" ref="SessionFactory" />
 </bean>

JSF 托管 Bean:

@ManagedBean
@ViewScoped
public class BJsfBeanX extends BCommon implements Serializable {
    @ManagedProperty(value = "#{GenericDAOService}")
        IGenericDAOHibernateService genericService; ...


public void onUpdatingDataRow(RowEditEvent ree) throws Exception {
    try{
                getGenericService().updateEntity(entity1); //line1: where updateEntity go throw layers and execute on DAO Layer: getSessionFactory().getCurrentSession().merge(object);
            //this line at DAO class does not execute commit on data base, the commit is executed when the control is back to the managedBean method line1
            getGenericService().updateEntity(entity2);//line2: this throw Exception, but there is nothing to do rollback `cause the entity1 (line 1) has been already committed
     }catch
}

我还尝试在服务层接口(interface)/服务层类上使用@Transactional,但是当控制权返回到 JSF ManagedBean 时,提交仍然发生。

场景 2。 *当从服务层删除 @Transactional 并在 JSF 托管 bean 方法上使用它时:*

@Transactional(rollbackFor = Exception.class)
    public void onUpdatingDataRow(RowEditEvent ree) throws Exception {

服务层不再提交数据库上的更改,但问题是所有流程都已完成(控制权返回到客户端),但对数据库的提交从未发生!请参阅我的第三个问题更新

最佳答案

您已经将 DAO 设为事务性的,因此每个 DAO 方法都会导致单独的事务也就不足为奇了。 DAO 方法永远不应该是事务性的。事务属于服务层。

关于java - 如何为每个请求使用一个事务 Spring + Hibernate + Spring Security + JSF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16723931/

相关文章:

spring - org.hibernate.LazyInitializationException : could not initialize proxy - no Session | DAO

hibernate - 当我在 hql 中使用 join 关键字时,为什么会得到 Path Expected for join

hibernate - 以编程方式处理 Grails 事务

java - 重新排序 int 数字中的数字以获得最小值

java - 如何通过单击抽屉导航 Activity 中的后退按钮从其他 fragment 返回特定 fragment

java - 将文件包含在具有不同名称的 war 中的简洁方法

java - JPA双向@ManyToMany关系: Assignment causes two inserts

java - Guice - 使用两种不同的实现注入(inject)对象

spring - 找不到构造函数的参数 0 - Spring Boot 和 Tomcat

java - Hibernate JPA 和 Spring javax.persistence.TransactionRequiredException : no transaction is in progress (2)