Wie zu verwenden einer Transaktion pro Anfrage Spring + Hibernate + Spring Security + JSF

Arbeite ich in einer web-Anwendung mit JSF 2.1 + Hibernate 4.1.7 + Feder 3.2.1 + Spring Security + SQLServer2012.
Funktioniert alles wunderbar, dh von CRUD-Operationen. Aber einige Methoden arbeiten müssen, um mit 2 oder mehr Personen (aktualisieren, hinzufügen, etc), zum Beispiel

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

Wenn ein Fehler Auftritt, Ausführung von Zeile #2 (create-Entität) muss ich das zusammengeschlossene Unternehmen (oder auch update, create) oder vor der DB-Funktion verwenden, um rollback, so dass die Daten auf meinem DB-achten Sie auf richtige

Ich bin mit der OpenSessionInViewFilter in Kombination mit @Transactional Spring-annotation.

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

Und in meinem GenericDAO ich habe

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

Was mir fehlt? weil, wenn die Linie #1 ausgeführt wird, werden die Daten zu DB.

Auszug aus meiner App LOG

beim ausführen von Zeile #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]
...

beim ausführen von Zeile #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

Vielen Dank im Voraus.

** vielen Dank für die Beantwortung, aktualisierte Frage: ****

Das ist mein 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>

Meine Data Access Layer: 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);
    }
}

Meine Business Logik Layer> 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);
        }
    }

Ich habe versucht mit @Transactional in meinem GenericDAOHibernateImpl nur GenericDAOHibernateImpl und Bussines-Schicht-Klasse beide, aber ich bekomme das gleiche Ergebnis die ganze Zeit

*DRITTE FRAGE UPDATE***

Ok, ich habe die service-Schicht

DAO-Schicht:

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

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

- Service-layer:

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

Ich habe auch versucht, mit der @Transactional auf service layer Interface /service-layer-Klasse, aber der commit ist noch passiert, wenn die Kontrolle kommt zurück, um JSF-managedBean.

Szenario 2.
*, Wenn Sie entfernt die @Transactional-von service-Schicht und mit auf der JSF managed bean Methode:*

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

dem Wechsel auf DB ist nicht verpflichtet, die von der service-Schicht mehr, ABER das problem ist, dass die Strömung fertig zu werden (Kontrolle kommt zurück zur client-Seite), aber die commit auf der DB tritt nie ein! Bitte Lesen Sie meine DRITTE FRAGE UPDATE

  • Was die transaction-manager benutzt du, und wie ist die konfiguriert? Auch die Frage, wie werden Ihre Transaktionen einzurichten. Von dem was ich verstehe das problem nicht zu sein scheinen mit der OpenSessionInViewFilter, sondern die Transaktion-setup, da es einen dedizierten verpflichten, nach der Zeile #1.
  • Das default-Verhalten OpenSessionInViewFilter ist, wickeln Sie die gesamte Anfrage mit einem nur-lese-Transaktion, um zu unterstützen, lazy loading in JSPs. Es spielt keine commit-Transaktionen und meint, dass die service-Schicht @Transactional Methoden Griff übertragen der Daten in die Datenbank. Sind Ihre merge() und create() Operationen geschieht innerhalb der gleichen @Transactional Methode? Wenn nicht, ich denke, Sie werden behandelt werden als selbständige Geschäfte.
  • Vielen Dank für die Beantwortung. Ich aktualisiert meine Frage für @Carsten auch.
InformationsquelleAutor daniel | 2013-05-23
Schreibe einen Kommentar