基于Eclipse Maven的Spring4/Spring-MVC/Hibernate4整合之十三:用Spring嵌套事务(Nested Transaction) 回滚并返回自定义Exception

来源:互联网 发布:曲阜党政网络问政平台 编辑:程序博客网 时间:2024/05/01 22:35

      目的 :

要实现事务回滚并且能返回自定义的Exception,

      首先我们先试验一下在transaction里运行:

@Transactionalpublic class xxx {/**** * 修改/删除/增加 Controller接口 * @param pvReq * @param pvLogin * @param pvLocale * @return * @throws Exception */public JSONData updateList(CommonReqUpdBean pvReq,String pvLogin, Locale pvLocale) throws Exception {JSONData lvRet=new JSONData();try {for (CommonReqUpdBean.DataBean bean : pvReq.data) {switch (bean.action) {case CommonReqUpdBean.ACTION_DELETE: {mTjDistributionDao.removeById((String)bean.key.id.get("fj_distribute_list"));break;}case CommonReqUpdBean.ACTION_EDIT: {TjDistributionList lvRec=getDistributionList((String) bean.key.id.get("fj_distribute_list"), pvLocale,null);CommonReqUpdBean.copySomeValuesToEntity(bean.data,lvRec, "fj_distribute_user","fj_part_rel_user");update(lvRec, false, pvLogin,pvLocale);break;}case CommonReqUpdBean.ACTION_INSERT: {TjDistributionList lvRec=CommonReqUpdBean.getBean(bean.data, TjDistributionList.class);TjDistributionList lvE = mTjDistributionDao.get(lvRec.getFjDistributeList());if (lvE != null) {lvRet.errCode = 1;lvRet.errMsg = MessageSourceHelper.getMessage("common.exists_failed", null);break;}update(lvRec, true, pvLogin,pvLocale);break;}}}} catch (ModifyDataException e) {mTjDistributionDao.clear();mTjDistributionDao.getSession().getTransaction().rollback();jsonDataFillErrMsg(lvRet, e);throw e;}finally{}return lvRet;}...}

     运行之, 返回错误信息 "Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started", 这是由于updateList运行完毕后, 事务管理器会自动commit,但由于我在Catch exception时已经rollback,但是就触发起这个"意料之外"的Exception, 因为这样,也就不能正常回传 JSONDATA数据.

    解决这个问题当然可以用上一节我们讲的新开一个session和transaction来操作, 但如果用当前session和transaction又如何解决呢? 这里要用到嵌套事务.

    要嵌套事务能正常工作必须满足以下条件: 你的数据库支持检查点(用Connection.getMetaData().supportsSavepoints()测试下), 配置事务管理时要加上嵌套事务支持:

<!-- 定义事务管理 -->    <bean id="transactionManager"        class="org.springframework.orm.hibernate4.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />        <property name="nestedTransactionAllowed">        <value>true</value>        </property>    </bean>

       然后给updatelist方法加上注释:@Transactional(propagation=Propagation.NESTED, rollbackFor=ModifyDataException.class), 这个注释做了两个声明,一个是"这里新开一个嵌套事务", 另一个是"抛出ModifyException时事务管理器要回滚此嵌套的事务"   

     于是我们将代码改为:

/**** * 修改/删除/增加 Controller接口 * @param pvReq * @param pvLogin * @param pvLocale * @return * @throws Exception */@Transactional(propagation=Propagation.NESTED, rollbackFor=ModifyDataException.class)public JSONData updateList(CommonReqUpdBean pvReq,String pvLogin, Locale pvLocale) throws Exception {JSONData lvRet=new JSONData();//mTjDistributionDao.getSession().getTransaction().begin();try {for (CommonReqUpdBean.DataBean bean : pvReq.data) {switch (bean.action) {case CommonReqUpdBean.ACTION_DELETE: {mTjDistributionDao.removeById((String)bean.key.id.get("fj_distribute_list"));break;}case CommonReqUpdBean.ACTION_EDIT: {TjDistributionList lvRec=getDistributionList((String) bean.key.id.get("fj_distribute_list"), pvLocale,null);CommonReqUpdBean.copySomeValuesToEntity(bean.data,lvRec, "fj_distribute_user","fj_part_rel_user");update(lvRec, false, pvLogin,pvLocale);break;}case CommonReqUpdBean.ACTION_INSERT: {TjDistributionList lvRec=CommonReqUpdBean.getBean(bean.data, TjDistributionList.class);TjDistributionList lvE = mTjDistributionDao.get(lvRec.getFjDistributeList());if (lvE != null) {lvRet.errCode = 1;lvRet.errMsg = MessageSourceHelper.getMessage("common.exists_failed", null);break;}update(lvRec, true, pvLogin,pvLocale);break;}}}//mTjDistributionDao.getSession().getTransaction().commit();} catch (ModifyDataException e) {mTjDistributionDao.clear();//mTjDistributionDao.getSession().getTransaction().rollback(); 不用自己回滚,交给事务管理器做jsonDataFillErrMsg(lvRet, e);throw e;}finally{}return lvRet;}


已成功将ModifyException回传至前端.

0 0