我正在使用 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 上的数据保持正确
我正在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。
从我的应用程序日志中提取
执行第 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,但我一直得到相同的结果
*第三个问题更新***
好的,我已经添加了服务层
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; ...
应用程序上下文.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 {
数据库上的更改不再由服务层提交,但问题是所有流程都已完成(控制权返回客户端)但对数据库的提交永远不会发生!请参阅我的第三个问题更新