2

私は 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 行目 (エンティティの作成) の実行中にエラーが発生した場合、マージされたエンティティ (または更新、作成) または以前の DB 関数を使用してロールバックを取得し、DB のデータが正しく維持されるようにする必要があります。

Spring アノテーションOpenSessionInViewFilterと組み合わせて使用​​しています。@Transactional

<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に送信されるためです。

アプリログから抜粋

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のみ、GenericDAOHibernateImpl と Bussines Layer クラスの両方で@Transactional を使用しようとしましたが、常に同じ結果が得られます

*3 番目の質問の更新***

OK、サービスレイヤーを追加しました

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
}

また、サービス層インターフェイス/サービス層クラスで @Transactional を使用しようとしましたが、制御が JSF managedBean に戻ったときにコミットが引き続き行われます。

シナリオ 2. *サービス層から @Transactional を削除し、JSF マネージド Bean メソッドで使用する場合: *

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

DB の変更はサービス層によってコミットされなくなりましたが、問題はすべてのフローが終了する (制御がクライアント側に戻る) ことですが、DB へのコミットは決して行われません! 私の 3 番目の質問の更新を参照してください。

4

4 に答える 4

3

DAO をトランザクション対応にしたので、各 DAO メソッドが個別のトランザクションを引き起こすことは驚くべきことではありません。DAO メソッドはトランザクション対応であってはなりません。トランザクションはサービス層に属します。

于 2013-05-25T12:02:54.357 に答える
1

わかりました、ありがとうございました。解決策は@Ryan Stewartが言ったとおりです。そして結論として:

  1. サービス層を使用する
  2. 同時に多くのエンティティを操作する必要がある場合は、ビジネス ロジック レイヤーではなく、サービス レイヤー側ですべてのエンティティを操作します。
  3. サービス層のメソッドがビジネスロジック層のメソッドに制御を返した後、何か問題があった場合、DB には何も保持されません。しかし、何も例外をトリガーしない場合、すべてのエンティティがコミットされます。

もう 1 つ、GenericDAOService から拡張された新しい DaoService を追加したので、この新しいサービスの実装には、ポイント 2 で述べた特定のロジックがあります。

皆様、あらためてありがとうございました。

于 2013-05-29T06:36:20.717 に答える