精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-12-05
首先我觉得这个问题和多个DAO没有关系,dhj1你可以看看Spring源码中的jpetstore的例子,在一个Service里面去调用多个DAO绝对不会有问题,下面是Spring源码中这个例子的配置文件的片断:
<!-- - A parent bean definition which is a base definition for transaction proxies. - It's marked as abstract, since it's not supposed to be instantiated itself. - We set shared transaction attributes here, following our naming patterns. - The attributes can still be overridden in child bean definitions. --> <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean> <!-- - JPetStore primary business object (default implementation);, as an inner bean wrapped - by an outer transactional proxy. The two bean definitions could have been separate, - but this is cleaner as there is no need to ever access the unwrapped object. --> <bean id="petStore" parent="baseTransactionProxy"> <property name="target"> <bean class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl"> <property name="accountDao" ref="accountDao"/> <property name="categoryDao" ref="categoryDao"/> <property name="productDao" ref="productDao"/> <property name="itemDao" ref="itemDao"/> <property name="orderDao" ref="orderDao"/> </bean> </property> <!-- Uncomment the following in order to enable mail sending aspect --> <!-- <property name="postInterceptors"> <list> <ref bean="emailAdvisor"/> </list> </property> --> </bean> 你要是再不信一个Service里面调用多个DAO是可以的,你不妨去直接把Spring的这个例子跑一下,看看有没有异常,我跑过,没有任何问题。 |
|
返回顶楼 | |
发表时间:2005-12-05
我用的是Hibernate3.0.5,Spring1.2.3,可以顺利的跑通jpetstore的例子。
|
|
返回顶楼 | |
发表时间:2005-12-05
我重建了楼主的环境,发现了一个奇怪的问题,大家一起讨论一下吧:
<!-- Add Transaction Manager here --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean> <bean id="baseTxProxy" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref local="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <!-- Add DAOs here --> <bean id="employeeDAO" class="com.bearingpoint.gdc.dao.impl.EmployeeDAOImpl" autowire="byName"> <property name="persistentClass"><value>${po.package}.Employee</value></property> </bean> <!-- Add Services here --> <bean id="employeeService" parent="baseTxProxy"> <property name="target"> <bean class="com.bearingpoint.gdc.service.impl.EmployeeServiceImpl" autowire="byName" /> </property> </bean> 然后是Service代码: /* * @see com.bearingpoint.gdc.service.EmployeeService#deleteEmployee(java.lang.String[]); */ public void deleteEmployee(String[] ids); throws Exception { for(int i = 0; i < ids.length; i++); { employeeDAO.deleteObjectById(Long.valueOf(ids[i]););; } throw new NullPointerException();; } 而后发现,这个时候,数据库是能够正确回滚的。但是如果我把最后一句改成:throw new Exception();数据库就不会回滚了。 莫非真的像前面readOnly所说,抛的异常必须是一个Unchecked Exception,Spring才会去处理? |
|
返回顶楼 | |
发表时间:2005-12-05
downpour 写道 而后发现,这个时候,数据库是能够正确回滚的。但是如果我把最后一句改成:throw new Exception();数据库就不会回滚了。 莫非真的像前面readOnly所说,抛的异常必须是一个Unchecked Exception,Spring才会去处理? 我也遇到了类似的问题 public void deleteEmployeesByIds(Long[] ids); throws Exception { //employeeDAO.dosomething throw new NullPointerException("aaaaa");; } 以下是spring的log 2005-12-05 19:01:03.421[DEBUG] TransactionAspectSupport.java:215 Getting transaction for com.frogfool.hr.service.EmployeeService.deleteEmployeesByIds 2005-12-05 19:01:03.500[DEBUG] TransactionAspectSupport.java:274 Invoking rollback for transaction on com.frogfool.hr.service.EmployeeService.deleteEmployeesByIds due to throwable [java.lang.NullPointerException: aaaaa] 若改为 public void deleteEmployeesByIds(Long[] ids); throws Exception { //employeeDAO.dosomething throw new Exception("aaaaa");; } spring的log 2005-12-05 18:55:55.000[DEBUG] TransactionAspectSupport.java:215 Getting transaction for com.frogfool.hr.service.EmployeeService.deleteEmployeesByIds 2005-12-05 18:55:55.062[DEBUG] TransactionAspectSupport.java:292 com.frogfool.hr.service.EmployeeService.deleteEmployeesByIds threw throwable [java.lang.Exception: aaaaa] but this does not force transaction rollback 难道只能出现Unchecked Exception? |
|
返回顶楼 | |
发表时间:2005-12-05
非常感谢各位的帮助! 问题基本得于解决!
|
|
返回顶楼 | |
发表时间:2005-12-05
我仔细研究了一下Spring的源码,发现它居然在rollback的时候对抛出的Exception做了处理:
/** * Handle a throwable, closing out the transaction. * We may commit or roll back, depending on our configuration. * @param txInfo information about the current transaction * @param ex throwable encountered */ protected void doCloseTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex); { if (txInfo.hasTransaction();); { if (txInfo.transactionAttribute.rollbackOn(ex);); { if (logger.isDebugEnabled();); { logger.debug("Invoking rollback for transaction on " + txInfo.joinpointIdentification(); + " due to throwable [" + ex + "]");; } try { this.transactionManager.rollback(txInfo.getTransactionStatus(););; } catch (RuntimeException ex2); { logger.error("Application exception overridden by rollback exception", ex);; throw ex2; } catch (Error err); { logger.error("Application exception overridden by rollback error", ex);; throw err; } } else { // we don't roll back on this exception if (logger.isDebugEnabled();); { logger.debug(txInfo.joinpointIdentification(); + " threw throwable [" + ex + "] but this does not force transaction rollback");; } // will still roll back if TransactionStatus.rollbackOnly is true this.transactionManager.commit(txInfo.getTransactionStatus(););; } } } 跟踪下去,看看它的rollbackOn函数,在实现transactionAttribute这个接口的类DefaultTransactionAttribute是这样处理的: /** * Default behavior is as with EJB: rollback on unchecked exception. * Additionally attempt to rollback on Error. * Consistent with TransactionTemplate's behavior. */ public boolean rollbackOn(Throwable ex); { return (ex instanceof RuntimeException || ex instanceof Error);; } 原来只处理RuntimeException的子类和Error,心里想,Spring不会那么死板吧,一看,果然发现它还有一个实现:RuleBasedTransactionAttribute /** * Winning rule is the shallowest rule (that is, the closest in the * inheritance hierarchy to the exception);. If no rule applies (-1);, * return false. * @see TransactionAttribute#rollbackOn(java.lang.Throwable); */ public boolean rollbackOn(Throwable ex); { if (logger.isDebugEnabled();); { logger.debug("Applying rules to determine whether transaction should rollback on " + ex);; } RollbackRuleAttribute winner = null; int deepest = Integer.MAX_VALUE; if (this.rollbackRules != null); { for (Iterator it = this.rollbackRules.iterator();; it.hasNext();;); { RollbackRuleAttribute rule = (RollbackRuleAttribute); it.next();; int depth = rule.getDepth(ex);; if (depth >= 0 && depth < deepest); { deepest = depth; winner = rule; } } } if (logger.isDebugEnabled();); { logger.debug("Winning rollback rule is: " + winner);; } // User superclass behavior (rollback on unchecked); // if no rule matches. if (winner == null); { logger.debug("No relevant rollback rule found: applying superclass default");; return super.rollbackOn(ex);; } return !(winner instanceof NoRollbackRuleAttribute);; } 用于处理那些你自定义的Exception,所以看来如果你的Service层喜欢往外抛自定义的异常的话,还是需要在配置文件的transactionAttribute节点底下定义你自己的rollback rules才能被Spring正确处理啊! |
|
返回顶楼 | |
发表时间:2005-12-06
downpour 写道 用于处理那些你自定义的Exception,所以看来如果你的Service层喜欢往外抛自定义的异常的话,还是需要在配置文件的transactionAttribute节点底下定义你自己的rollback rules才能被Spring正确处理啊! downpour分析得很精彩,的确是这样!我定义一个BeanNotFoundException ,并在transactionAttributes的props中配置这个checked Exception,那么在serviceImpl中throw也可以正确回滚的!同样,spring的hibernateTemplate的回调中只允许抛出unchecked Exception,TransactionTemplate 会在一个unchecked异常抛出时触发一个rollback, 或者当事务被应用程序通过TransactionStatus标记为rollback-only. 1、 public class BeanNotFoundException extends Exception { public BeanNotFoundException(); { super();; } public BeanNotFoundException(String message); { super(message);; } } 2、 <props> <prop key="*">PROPAGATION_REQUIRED,-BeanNotFoundException </prop> <prop key="load*">PROPAGATION_REQUIRED,-BeanNotFoundException </prop> </props> 3、throw new BeanNotFoundException ("Exception");; 如果要允许任何checked的应用异常在callback代码中抛出,可以定义HibernateInterceptor,TransactionInterceptor来代替TransactionProxyFactoryBean. 缺点:如下配置interceptorNames,这样就不具有TransactionProxyFactoryBean的重用事务策略功能。因为它必须为指定事务方法定义在哪一个接口或类中. 4、<bean id="myTransactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="transactionAttributeSource"> <value> product.ProductService.increasePrice*=PROPAGATION_REQUIRED product.ProductService.someOtherBusinessMethod=PROPAGATION_MANDATORY </value> </property> </bean> <bean id="myProductServiceTarget" class="product.ProductServiceImpl"> <property name="productDao"> <ref bean="myProductDao"/> </property> </bean> <bean id="myProductService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>product.ProductService</value> </property> <property name="interceptorNames"> <list> <value>myTransactionInterceptor</value> <value>myProductServiceTarget</value> </list> </property> </bean> |
|
返回顶楼 | |
发表时间:2005-12-06
downpour 写道 莫非真的像前面readOnly所说,抛的异常必须是一个Unchecked Exception,Spring才会去处理? 不是偶说的,是Spring就这样处理的,它的文档里面有那么详细地描述,难道你们都从来不看?浪费啊...... |
|
返回顶楼 | |
发表时间:2005-12-06
引用 不是偶说的,是Spring就这样处理的,它的文档里面有那么详细地描述,难道你们都从来不看?浪费啊...... 老大,没发现文档里有相关的说法啊 看来以后要认真读文档。 |
|
返回顶楼 | |
发表时间:2005-12-07
downpour 写道 老大,没发现文档里有相关的说法啊 看来以后要认真读文档。 spring的文档质量和代码质量都是很不错的: http://static.springframework.org/spring/docs/1.2.x/reference/transaction.html 引用 While the EJB default behavior is for the EJB container to automatically roll back the transaction on a system exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically on an application exception (checked exception other than java.rmi.RemoteException). While the Spring default behavior for declarative transaction management follows EJB convention (roll back is automatic only on unchecked exceptions), it's often useful to customize this. 引用 In this example, note that the value for the insert* mapping contains a rollback rule. Adding -MyCheckedException here specifies that if the method throws MyCheckedException or any subclasses, the transaction will automatically be rolled back. Multiple rollback rules can be specified here, comma-separated. A - prefix forces rollback; a + prefix specifies commit. (This allows commit even on unchecked exceptions, if you really know what you're doing!) |
|
返回顶楼 | |