1 2 Previous Next 17 Replies Latest reply: Sep 29, 2011 11:48 AM by André Simões RSS

<xa-datasource>

André Simões Newbie

Hi.

 

I want to know if it possible to control the transaction roll back on a multiple transaction case.

 

I have two database sources. When i do an update on db1 and db2, if update db2 fail, both do roll back.

This is ok, in most of cases...

 

Is this scenario possible?

update db1 ok

update db2 nok

 

commit db1

rollback db2

 

How can i configure it?

 

I had already tried

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

 

with no success.

 

The main idea is to be possible to choose when do a full roll back or just parcial.

 

 

I'm using JBOSS 5.1.0 AS, @EJB3, @PersistenceContext, @NamedQueries

  • 1. Re: <xa-datasource>
    Tom Jenkinson Master

    Hi André,

     

    Its not entirely clear to me what you are trying to achieve here sorry! Perhaps you want two transactions for the separate database updates?

     

    Tom

  • 2. Re: <xa-datasource>
    Tom Jenkinson Master

    It could also be that you need nested transactions, which JBossTS does support but the JTA API doesn't so that could be an option but it would probably require a bit of coding on your part: http://docs.jboss.org/jbosstm/5.0.0.M1/guides/arjunacore-development_guide/ch04.html#d0e1845

     

    For instance you would not be able to do this through UserTransaction

  • 3. Re: <xa-datasource>
    André Simões Newbie

    Hi.

     

    I already found the solution, but the problem was:

     

    If I have a two-phases commit transaction, by default, if one of then fail, we got a full rollback.

    but how to just rollback the  invalid commit?

     

    I managed to control this situation with the following procedure

     

    @Resource
    private UserTransaction userTransaction;
    
    ......
    
    try {
                userTransaction.begin();
    
                .................
    
                userTransaction.commit();
    
            } catch (Exception e) {
                try {
                    userTransaction.rollback();
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } 
            }
    

     

     

    Maybe I forgot to say that I'm making the transaction inside a stateless ejb and calling a second stateless ejb to make the second transaction.

  • 4. Re: <xa-datasource>
    mazz Master

    Why would you want to do that? If you are using 2PC, and you have multiple resources registered in a transaction and one fails, by definition you want them all to rollback right? The whole purpose of this XA/2PC stuff is to NOT have it rollback one but commit another I thought. That would put it in a bad state.

     

    If you really want them to be isolated from each other, just put them in different transactions. From a stateless session bean, the typical way to do this kind of thing is to utilize the REQUIRES_NEW transaction flag (perhaps in conjunction with NEVER).

  • 5. Re: <xa-datasource>
    André Simões Newbie

    In 90% of the cases you are right.

    But imagine yo have two database sources, one with critical data (db1), and all of the redundance and security involved, and another (db2) for statistics and other data not so critical.

     

    When you do a two phasis commit, you can not allow that db2 failure causa a db1 failure to commit.

     

     

    I had tried

     

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    

     

    but  with no success...

  • 6. Re: <xa-datasource>
    Jonathan Halliday Master

    When you have a 2PC you MUST allow the db2 failure to rollback the db1 update. That's the A in ACID. But it seems you're not trying to build a 2PC transaction, you're trying to use a 2PC transaction manager to build an extended transaction. That's hard, because they are not intended to do that. Arguably they're intended explicitly NOT to do it. Any solution you build is going to have to deal with one of two corner cases: you've already committed the critical db1 update and then the non-critical db2 updates fails. How do you detect this and use the data in db1 to update db2 to bring them back into sync at a later time, or allow your system to continue to tolerate the inconsistency indefinitely? Or, you've already updated db2 and then the critical db1 update fails. How do you detect this and remove the entry in db2? Now make your solution work even if the system crashes at the worst possible moment. Still think you've found a solution? I bet it involves writing a lot of custom business logic for data reconciliation or tolerating inconsistent data.

  • 7. Re: <xa-datasource>
    Mark Little Master

    Look at XTS then, because what you are after is not an ACID transaction.

  • 8. Re: <xa-datasource>
    André Simões Newbie

    Ok, maybe i'm not explaining myself very well.

     

    This is an possible example of an applications what shows what i'm trying to do.

     

    An remote app calls mergeBoth(data) from the remote interface of Bean1.

     

    @Stateless(name = "Bean" mappedName = "a-Bean")
    public class Bean1 impements Bean{
         
         @EJB(mappedName = Bean2/local")       
         private Bean2 beanDbCritLocal;
    
         @EJB(mappedName = Bean3/local")       
         private Bean3 beanDbNotCritLocal;
    
         @Override    
         public void mergeBoth(SomeData data){
    
              DataForDB1 data1 = new DataForDB1();
              DataForDB2 data2 = new DataForDB2();
    
              data1.setparms(data.getparams());     //different params
              data2.setparams(data.getparams());   //different params 
         
              beanDbCritLocal.merge(data1);
              beanDbNotCritLocal.merge(data2);
         }
    }
    

     

     

    Example of data:

    Db1 are in a private network and have minute log of temperature

    Db2 are for public acess and have current temperature.

  • 9. Re: <xa-datasource>
    Andrew Dinn Master

    André Simões wrote:

     

    In 90% of the cases you are right.

    But imagine yo have two database sources, one with critical data (db1), and all of the redundance and security involved, and another (db2) for statistics and other data not so critical.

     

    When you do a two phasis commit, you can not allow that db2 failure causa a db1 failure to commit.

     

    No,in 100% of cases he is right.

     

    If you are willing to allow the data in db2 to be out of synch with the data in db1 (i.e.roll forward db1 but roll back db2) then there is no reason to run them in the same transaction. Make all your changes to db1 and commit them then make all the changes to db2 and commit them.

     

    If it is important that the two databases remain in synch then you either want them both to be updated or both to fail otherwise they will contain inconsistent information. That's what a common transactionand 2 phase commit gives you,either all changes are amdero none. In this case making the claim that the data in db1 is critical and the data in db2 is not is an inconsistent position. Either you have your cake or you eat it but not both.

     

    If you cannot see why this is so then you need to go back to basics and read a good book on transactions (I suggest you try the one written by Mark Little :-)

  • 10. Re: <xa-datasource>
    Tom Jenkinson Master

    I may be wrong, but it sounds a little bit like you are saying the data in DB2 is non critical and it doesn't matter to you whether or not (in your example) data2 is persisted? In which case, maybe you don't want to use XA for DB2?

  • 11. Re: <xa-datasource>
    André Simões Newbie

    That's it!

    Maybe the 2pc is not what i'm looking for.

    I had tryed to use also <local-tx-datasource> but a rollback on db2 continues to causa a rollback on db1.

     

    Remember that the solution that i show in my second post solve my problem.

     

    I'm not a database expert and i just want to commit data to two different db in the fastest way...

  • 12. Re: <xa-datasource>
    mazz Master

    OK, here is how you do it correctly (note: I am assuming I understand you as saying you explicitly will allow db2 to fail and not affect the commit of db1).

     

    Just annotate "mergeBoth" with "@TransactionAttribute(TransactionAttributeType.NEVER)"

     

    Thus, when mergeBoth is called, there is no transaction created yet.

     

    Now, your Bean2 and Bean3 merge methods must be annotated with REQUIRES_NEW.

     

    And Ta-DA! You got what you want. I do this kind of thing all the time. Now what happens is, if that first call to db1 fails, you don't do db2 (which again is what I assume you want). That's because the exception bubbles out and you never even do the db2 call. If the first call to db1 succeeds, it doesn't matter what db2 does, that REQUIRES_NEW method has ended, the transaction has been committed, and it is done.

     

    This is what I meant earlier when I said you probably want to use REQUIRES_NEW in conjunction with NEVER. In this case, you never even ENLIST 2PC here! Which makes it, presumably, faster too, since you never have to worry about all the additional phases (since you are only ever enlisting a single resource at any one time here)

  • 13. Re: <xa-datasource>
    André Simões Newbie

    This is what i want to do!

     

    I will try again REQUIRES_NEW but with "@TransactionAttribute(TransactionAttributeType.NEVER)" and will give some feedback.

  • 14. Re: <xa-datasource>
    Jonathan Halliday Master

    That's a seductively simple solution, but actually only correct if the business requirements allow for it. If the update of the non critical db fails, the implications and necessary compensation steps are business case specific. If it can be allowed to remain out of sync with db1 indefinitely, then the simple solution is adequate. If not, you need to consider how it's going to be resynced, as you don't have an automatic tx recovery system to help you with that.

1 2 Previous Next