我正在使用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。
从我的App LOG中提取
执行第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);
}
}
我的业务逻辑层&gt; 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; ...
的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
}
我也尝试在服务层接口/服务层Class上使用@Transactional,但是当控制权回到JSF managedBean时,仍然会发生提交。
场景2。 * 从服务层删除@Transactional并在JSF托管bean方法上使用它时: *
@Transactional(rollbackFor = Exception.class)
public void onUpdatingDataRow(RowEditEvent ree) throws Exception {
数据库的更改不再由服务层提交,但问题是所有流程都已完成(控制权返回到客户端),但是对DB的提交永远不会发生!请参阅我的第三个问题更新
答案 0 :(得分:3)
您已经创建了DAO事务,因此每个DAO方法导致单独的事务都不足为奇。 DAO方法永远不应该是事务性的。交易属于服务层。
答案 1 :(得分:1)
好的,谢谢大家的时间。解决方案是 @Ryan Stewart 所说的。最后:
还有一件事,我添加了一个从我的GenericDAOService扩展的新DaoService,所以在这个新的服务实现中,我有第2点提到的特定逻辑。
再次感谢大家。
答案 2 :(得分:0)
要获得回滚,您必须确保以下事项:
@Transactional(rollbackFor=Exception.class)
public void doInTransaction() {
getDAOImplEntity1().merge(); // line 1
getDAOImplEntity2().create(); // line 2
getDAOImplEntity3().delete(); // line 3
}
第二个代码段(例外):
@Transactional(rollbackFor=Exception.class)
public void doInTransaction() throws Exception {
try{
getDAOImplEntity1().merge(); // line 1
getDAOImplEntity2().create(); // line 2
getDAOImplEntity3().delete(); // line 3
} catch (Exception ex) {
Logger.getLogger(BeanJSF1.class.getName()).log(Level.SEVERE, null, ex);
throw ex; // Very important!!! Without this, exception do not cross transaction boundaries (`doInTransaction()` method) and Spring wan't do rollback for you
}
}
答案 3 :(得分:0)
好的,看到这个后我的猜测是问题是Spring-JSF集成之一。问题可能是由于您使用的是Spring事务管理器。但是您的Bean由JSF(@ManagedBean
和@ManagedProperty
)管理和注入。这可能会导致一些意外的事务行为。
为了解决这个问题,我的建议是使用@Component
代替@ManagedBean
和@Autowired
或{{1}将所有bean(或至少与交易相关的bean)置于spring controll下而不是@Inject
。
要仍然能够通过EL从JSF访问您的Beans,您需要将@ManagedProperty
添加到您的faces-config中。
SpringBeanFacesELResolver
以下是更详细说明的基本教程:http://www.mkyong.com/jsf2/jsf-2-0-spring-integration-example/
即使这不能解决眼前的问题,它仍然是有益的,使项目更加一致,不易出错。