私は 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 番目の質問の更新を参照してください。