Announcement Announcement Module
Collapse
No announcement yet.
Will no-rollback-for work for Runtime Exceptions? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Will no-rollback-for work for Runtime Exceptions?

    The Spring reference guide states:

    "..the Spring Framework's transaction infrastructure code will, by default, only mark a transaction for rollback in the case of runtime...exceptions.
    It is also possible to specify 'no rollback rules', for those times when you do not want a transaction to be marked for rollback when an exception is thrown. "


    It is not clear if I can disable roll-backs on particular implementations of RuntimeException. I don't see why it shouldn't be possible, but it looks like when I try to exclude a particular RTE from rollbacks, the rollback still occurs. I don't use checked exceptions at all, and a couple of my "business" exceptions are also RTEs. Those are conditions such as "duplicate order", that actually represent legitimate business cases rather than errors but are more efficiently and easily handled as exceptions since they allow me to quickly unwind the call stack and redirect control to the designated handler far away from the source of the condition. In one case, I don't want to roll back the transaction on such business exception because the DB stored procedure still does something useful in the case of a duplicate order and returns an appropriate code. I analyze the code at the service level and throw a RTE that the application's handler eventually catches and displays the view appropriately (performs an alternative action.) The service API is, of course transactional, and must roll-back on all system errors, except this given "business" RTE.

    The service calls a method on a DAO to save the order. That method may throw a subclass of my BusinessRuleException (RTE) that I don't want to roll back on. With any other exception, I want the transaction to roll back. Here's what the dao method looks like:

    Code:
        public Order saveOrder(Order order) {
            if (saveOrderProc == null) {
                init();
            }
            Map<String, Object> params = new HashMap<String, Object>(1);
            params.put(IN_PARAM_ORDER, new OrderToSqlType(order));
            Map m = saveOrderProc.execute(params);
            long errcode = (Long) m.get(OUT_ERROR_CODE);
            if (errcode != 0L) {
                // don't want to roll back, just catch and redirect to appropriate view
                throw new DuplicateOrderException(ERR_MSG_DUPLICATE_ORDER);
            }
            order.setId((Long) m.get(OUT_PARAM_ORDER_ID));
            return order; // return updated order object w/newly assigned ID
        }
    In my txn advice definition, I use the following:

    Code:
    <tx:method name="save*" rollback-for="Throwable" no-rollback-for="BusinessRuleException" />

    where BusinessRuleException is the superclass for the business exception that is actually being thrown, and it itself extends RuntimeException.

    It seems that the transaction still fails to commit if the method throws a BusinessRuleException (its subclass.) Does "no-rollback-for" only work for checked exceptions? Is it possible to disable rollbacks for RTEs? Or, should I look for another reason for the commit not working properly?

    Thanks for any clarification.
    Last edited by constv; Jul 2nd, 2008, 02:16 PM.

  • #2
    Well you have some contradiction configuration don't you... You want to rollback everything (Throwable) so that is matching everything. I would start by removing that...

    Comment


    • #3
      Originally posted by Marten Deinum View Post
      Well you have some contradiction configuration don't you... You want to rollback everything (Throwable) so that is matching everything. I would start by removing that...
      Thanks for the reply. Actually, here's an excerpt from the Spring Reference Guide:

      When the Spring Framework's transaction infrastructure has caught an exception and is consulting any configured rollback rules to determine whether or not to mark the transaction for rollback, the strongest matching rule wins. So in the case of the following configuration, any exception other than an InstrumentNotFoundException would result in the attendant transaction being marked for rollback.

      <tx:advice id="txAdvice">
      <tx:attributes>
      <tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
      </tx:attributes>
      </tx:advice>

      It's taken from http://static.springframework.org/sp...e-rolling-back

      Nevertheless, I had tried, originally, a definition without the roll-back attribute at all - since, like I said, I only use RTEs, and by default, Spring rolls the txn back on any RTE. So, I figured, the "no-rollback-for" attribute specifically is used to exclude the hand-picked exceptions from the rollback rule.


      Anyway, I had just talked to the guy who wrote the stored procedure I am calling, we'll see if there's anything strange going on there...

      Comment


      • #4
        Hello,

        Could you post example of your code, because I have the same problem, but i have a problem of transaction wich launch a rollbackException...

        thanks

        Comment


        • #5
          the same problem with no-rollback-for / unchecked exception

          Hello,
          i have the same problem
          with no-rollback-for for my own unchecked exception (MessageBusinessException). always the rollback happen.

          <tx:advice id="swapTxAdvice" transaction-manager="swapTransactionManager">
          <tx:attributes>
          <tx:method name="*" propagation="REQUIRED" no-rollback-for="com.swap.service.MessageBusinessException"/>
          </tx:attributes>
          </tx:advice>
          <aop:config>
          <!-- We want to select all service except ImportDataService and affect SwapTransactionManager configuration-->
          <aopointcut id="swapServicePointcut" expression="execution(public * com.swap.service..*.*(..))"/>
          <aop:advisor advice-ref="swapTxAdvice" pointcut-ref="swapServicePointcut" />
          </aop:config>

          <bean id="swapTransactionManager"
          class="org.springframework.orm.hibernate3.Hibernat eTransactionManager">
          <property name="sessionFactory" ref="SwapSessionFactory" />
          </bean>

          if you have got a solution of this problem i will be very greatfull.

          thx in advance

          Comment


          • #6
            Rollback exception

            Hey fellow Spring enthusiasts!

            I am working with SWF-faces (extending the SWF-booking sample).

            I am adding users with authority etc to the Dbase with embedded address
            and associated privilege table. Fine so far.. I am able to create and update
            users with all the related info and log them in off one input form with fields such as

            user.name
            user.homeAddress.streetAddress
            etc...

            At this point I am trying to do Exception Handling. I want to prevent the ROLE_SUPERVISOR
            from adding a new user with a previous users username (native pk).

            I've tried to implememt the code from the reference manual 5.6.1. Handling a business exception with a POJO action>

            So... in the user-flow.xml

            Code:
               <var name="userFm" class="org.springframework.webflow.samples.booking.User"  />
            
            	<input name="searchCriteria" required="true" />
            	<input name="referenceData" required="true" />
            
            
            	<view-state id="reviewUsers">
                    <on-render>
            		  <evaluate expression="userService.listUsers(searchCriteria)" result="viewScope.users" result-type="dataModel" />
                    </on-render>
                    <transition on="sort">
                        <set name="searchCriteria.sortBy" value="requestParameters.sortBy" />
                        <render fragments="users:usersFragment" />
                    </transition>
            		<transition on="previous">
            			<evaluate expression="searchCriteria.previousPage()" />
            			<render fragments="users:usersFragment" />
            		</transition>
            		<transition on="next">
            			<evaluate expression="searchCriteria.nextPage()" />
            			<render fragments="users:usersFragment" />
            		</transition>
            		<transition on="select" to="enterUserDetails">
            			<set name="flowScope.userFm" value="users.selectedRow" />
            		</transition>
            		<transition on="delete">
            			<evaluate expression="userService.deleteUser(users.selectedRow)" />
            			<render fragments="users:usersFragment" />
            		</transition>
            
            		<transition on="addUser" to="enterUserDetails" >
                        <evaluate expression="userService.initUser()" result="userFm" />
                    </transition>
                </view-state>
            
                <action-state id="createUser" >
                        <evaluate expression="userService.createUser(userFm,flowRequestContext)" />
                        <transition on="success" to="reviewUsers" />
                        <transition on="error" to="enterUserDetails" />       
            	</action-state>
            
                <view-state id="enterUserDetails"  model="userFm">
            		<transition on="proceed" to="createUser" />
            		<transition on="cancel" to="reviewUsers" bind="false" />
            	</view-state>


            in my JpaUserService...

            Code:
               @Transactional(readOnly = true) //(noRollbackForClassName="user")
                 public String createUser(User user,RequestContext context ){
            
                 MessageContext messages = context.getMessageContext();
                 try{
            
                    Md5Encoder m = new Md5Encoder();
                    String strMd5 = m.md5Encrypt(user.getPassword());
                    user.setPassword(strMd5);
            
                    user.addPrivilege(user.getAuthority());
            
                    em.persist(user);
                    em.flush();     // this commits
            
                    return "success";
                    
                 }
                 catch(Exception duplicate){
                     messages.addMessage(new MessageBuilder().error().defaultText("this username is already taken!").build());
            
                     return "error";
                     
                 }
                }
            The page has a command button that submits..

            Code:
            	<sf:validateAllOnClick>
            		<sf:commandButton id="proceed" action="proceed" processIds="*" value="Proceed"/>*
            	</sf:validateAllOnClick>

            When I run this I get the following error(I'm just showing the relevant edited msg):

            Exception

            org.springframework.web.util.NestedServletExceptio n: Request processing failed;
            nested exception is org.springframework.webflow.execution.ActionExecut ionException:
            Exception thrown executing [[email protected] targetAction =
            [[email protected] expression = userService.createUser(userFm,flowRequestContext),
            resultExposer = [null]], attributes = map[[empty]]] in state 'createUser' of flow
            'user' -- action execution attributes were 'map[[empty]]'


            root cause

            org.springframework.webflow.execution.ActionExecut ionException: Exception thrown executing
            [[email protected] targetAction = [[email protected] expression =
            userService.createUser(userFm,flowRequestContext), resultExposer =
            [null]], attributes = map[[empty]]] in state 'createUser' of flow 'user'
            -- action execution attributes were 'map[[empty]]'

            root cause

            org.springframework.binding.expression.EvaluationE xception:
            An ELException occurred getting the value for expression
            'userService.createUser(userFm,flowRequestContext) ' on context
            [class org.springframework.webflow.engine.impl.RequestCon trolContextImpl]

            root cause

            javax.el.ELException: org.springframework.transaction.TransactionSystemE xception:
            Could not commit JPA transaction; nested exception is javax.persistence.RollbackException:
            Transaction marked as rollbackOnly

            root cause

            org.springframework.transaction.TransactionSystemE xception:
            Could not commit JPA transaction; nested exception is javax.persistence.RollbackException:
            Transaction marked as rollbackOnly

            root cause

            javax.persistence.RollbackException: Transaction marked as rollbackOnly


            I've tried different things to work around including checking in the Db for a user
            and setting a isUniqueName boolean into the user model, however the sequence of events
            would require entering the same form twice to accomplish this,.. Uuuuugh!

            ( then I would use the 4.10. Validating a model approach as in the manual..as in

            Code:
            	   public class Booking {
            	       private Date checkinDate;
            	       private Date checkoutDate;
            	       ...
            
            	       public void validateEnterBookingDetails(ValidationContext context) {
            		   MessageContext messages = context.getMessageContext();
            		   if (checkinDate.before(today())) {
            		       messages.addMessage(new MessageBuilder().error().source("checkinDate").
            			   defaultText("Check in date must be a future date").build());
            		   } else if (!checkinDate.before(checkoutDate)) {
            		       messages.addMessage(new MessageBuilder().error().source("checkoutDate").
            			   defaultText("Check out date must be later than check in date").build());
            		   }
            	       }
            	   }
            
               
               )
            Doing this Logically I would have posted the bean, caught the db unique constraint exception in
            my DbManager and responded with an appropriate message back to the Servlet and hence dispay the same page again with the message.

            How can I essentially do te same thing with Webflow ?

            How is the Transaction marked as Rollback only? Does this prevent what I want to do? Is there a work around?

            Any Ideas my friends?

            Comment

            Working...
            X