Announcement Announcement Module
Collapse
No announcement yet.
bean id specific tx:advice Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • bean id specific tx:advice

    Hi,
    I am trying to use 2 different datasources and transaction managers for 2 different instance of a dao bean. I am going to define 2 beans with 2 different ids in application context.

    I would like to know how to specify the bean id while configuring the aop to use the transaction manager.

    The example in the spring reference documentation deals only with one bean to participate in transaction and looks like it get applied to all that matches the pointcut.

    Thanks

  • #2
    Originally posted by jsrinivas View Post
    Hi,
    I am trying to use 2 different datasources and transaction managers for 2 different instance of a dao bean. I am going to define 2 beans with 2 different ids in application context.

    I would like to know how to specify the bean id while configuring the aop to use the transaction manager.

    The example in the spring reference documentation deals only with one bean to participate in transaction and looks like it get applied to all that matches the pointcut.

    Thanks
    You only need one transaction manager.

    You can wire up different instances of your dao's to different datasources (datasource definitions elided for clarity):

    Code:
    <bean id="oracleDao" class="com.MyDao">
      <property name="dataSource" ref="oracleDataSource"/>
    </bean>
    <bean id="postgresDao" class="com.MyDao">
      <property name="dataSource" ref="postgresDataSource"/>
    </bean>
    However, if you are trying to write to both datasources as part of a single transaction, you need to apply your transaction semantics at a higher level than the dao methods. Otherwise the transaction won't span both calls.

    Assume you have the following service:

    Code:
    public class MyService
    {
        private MyDao dao1;
        private MyDao dao2;
    
        public void setDaoOne(MyDao dao)
        {
            this.dao1 = dao;
        }
    
        public void setDaoTwo(MyDao dao)
        {
            this.dao2 = dao;
        }
    
        public void doStuff()
        {
            dao1.doStuff();
            dao2.doStuff();
        }
    }
    Wired up as:

    Code:
    <bean id="myService" class="com.MyService">
        <property name="daoOne" ref="oracleDao"/>
        <property name="daoTwo" ref="postgresDao"/>
    </bean>
    Then you would apply a point cut across the service method to apply the transaction semantics, which would then enlist both dao's (transaction manager definition elided for clarity):

    Code:
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <!-- the transactional semantics... -->
            <tx:attributes>
                <tx:method name="do*" propagation="REQUIRED"/>        
            </tx:attributes>
        </tx:advice>
    
        <aop:config>
          <aop:pointcut id="doStuff" expression="execution(* com.MyService.doStuff(..))"/>      
          <aop:advisor advice-ref="txAdvice" pointcut-ref="doStuff"/>    
        </aop:config>

    Comment


    • #3
      bean id specific tx:advice

      Thanks for the detailed explanation chudak.

      I am using org.springframework.jdbc.datasource.DataSourceTran sactionManager as my transaction manager. So I have to use 2 transaction managers each configured with different datasources.

      I also need the transaction to work at the dao level.

      In the meantime, I extended the dao to create a dummy class without overriding any methods (just to give it a different class name) and used 2 different classes in the tx configuration like the following.

      <aop:config>
      <aopointcut id="oneDAOOperation"
      expression="execution(* my.package.OneDAO.*(..))" />
      <aop:advisor advice-ref="oneTxAdvice"
      pointcut-ref="oneDAOOperation" />
      </aop:config>

      <aop:config>
      <aopointcut id="twoDAOOperation"
      expression="execution(* my.package.twoDAO.*(..))" />
      <aop:advisor advice-ref="twoTxAdvice"
      pointcut-ref="twoDAOOperation" />
      </aop:config>

      This does have some other problem. Only one dao call is commiting and the other is getting rolledback.

      Thanks

      Comment


      • #4
        In your case, maybe it makes more sense to use the @Transactional annotations rather than the aop pointcuts. That way, both dao's will be transactional and you won't have the issue with the point cut and the two tx managers.

        I can't comment on the correctness of your approach because I don't know the whole story but I suspect that you are defining your 'unit of work' incorrectly with respect to your dao's.

        Comment


        • #5
          wiring up two daos in an aspect

          guys,
          I need to implement the same, wiring of two or more daos in one aspect like your doStuff.
          created the properties in service bean and assigned the setters and getters for the Daos. What is happening is .. It is rolling back only the failed one, the rest all are going into database. BTW, I'm using the same datasource(JTA), but different DAOs. Any other help is great !!!

          Thanks.

          Comment


          • #6
            Are you sure you have the transactions applied at the service method level and not at the dao level?

            Comment


            • #7
              Thanks for the response.
              Yes. I'm sure.
              <CODE><bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor .NameMatchTransactionAttributeSource">
              <property name="properties">
              <props>
              <prop key="get*">PROPAGATION_REQUIRED,+RuntimeException</prop>
              <prop <prop key="tol*">PROPAGATION_REQUIRED,+RuntimeException,-AppException</prop>
              </props>
              </property>
              </bean>
              </CODE>

              Please let me know, if I miss anything.
              Thanks.

              Comment


              • #8
                Never done this myself but I guess that you have to use a JtaTransactionManager if you transaction spans multiple resources (in this case, two databases). If I understood you correctly you are using two transaction managers independently of each other which wont work.

                Taken from Chapter 9 in the reference manual, transaction management.

                Typically you need an application server's JTA capability only if you need to enlist multiple transactional resources, and for many applications being able to handle transactions across multiple resources isn't a requirement.

                Comment


                • #9
                  Originally posted by johras View Post
                  Never done this myself but I guess that you have to use a JtaTransactionManager if you transaction spans multiple resources (in this case, two databases). If I understood you correctly you are using two transaction managers independently of each other which wont work.

                  Taken from Chapter 9 in the reference manual, transaction management.
                  You are correct and I didn't even notice the comment above:

                  Originally posted by jsrinivas
                  I am using org.springframework.jdbc.datasource.DataSourceTran sactionManager as my transaction manager. So I have to use 2 transaction managers each configured with different datasources.
                  As johras mentions, you cannot use a datasource transaction manager to manage a transaction across two datasources. You HAVE to use the JtaTransactionManager and your datasources need to be transaction aware (e.g. transactionawaredatasourceproxy).

                  Comment


                  • #10
                    sorry for the confusion.
                    I am using single JTA and one datasource(database). I have multiple daos for the same datasource. I need to run a particular set of dao methods in a loop.
                    what I need is, I need to roll back the iteration, if any of the daos in the loop fails and continue with the next iteration.
                    What I achieved is.. It is not getting rolled back all the daos within the iteration. It is stopping at that point and going forward with the next iteration.

                    for example,
                    I have daoMethod1, daoMethod2, daoMethod3 and calling these three in a loop
                    for (Object obj:Objs.getObj){
                    {
                    try{
                    daoMethod1;
                    daoMethod2;
                    daoMethod3;
                    }catch(Exception ex){
                    //absorb and log
                    }
                    }
                    What is happening here is ... daoMethod1 is not getting rolled back, when daoMethod2 is failing and going for the next iteration, so on.
                    This loop is my aspect and I declared these 3 daos as properties in the method.

                    I tried with savepoint too. But I got below Exception,
                    main ~#[Spring Bean : Mybean, method : processMybean] Transaction object [org.springframework.transaction.jta.JtaTransaction Object@5ae1e7] does not support savepoints#~
                    org.springframework.transaction.NestedTransactionN otSupportedException: Transaction object [org.springframework.transaction.jta.JtaTransaction Object@5ae1e7] does not support savepoints
                    at org.springframework.transaction.support.DefaultTra nsactionStatus.getSavepointManager(DefaultTransact ionStatus.java:164)
                    at org.springframework.transaction.support.AbstractTr ansactionStatus.createSavepoint(AbstractTransactio nStatus.java:170)

                    Comment


                    • #11
                      If you want to fail or commit on each iteration, the iteration loop needs to be outside of the transaction, the logic in the iteration needs to be wrapped in the transaction, e.g.

                      Code:
                      while(true)
                      {
                          // start new transaction    
                          dao1.doStuff();
                          dao2.doStuff();
                          // end transaction
                      }
                      This is tricky because transactional proxies and annotations don't work when you call a method on the same object, they only work when you are entering the object.

                      What this means is that the method that does the work needs to be in another object than the method that runs the loop so you can apply the proxy to the work and not the loop.

                      Code:
                      public class Looper
                      {
                          private Worker worker;
                          public void setWorker(Worker worker)
                          {
                              this.worker = worker;
                          }
                         
                          public void loop()
                          {
                              while (true)
                              { 
                                  try
                                  {
                                      worker.work();
                                  }
                                  catch(Throwable t){// ignore or log}
                              }
                          }
                      }
                      
                      public interface Worker
                      {
                          public void work();
                      }
                      
                      public class WorkerImpl implements Worker
                      {
                          private Dao dao1;
                          private Dao dao2;
                      
                          // Setters elided
                       
                          @Transactional(propagation=Propagation.REQUIRES_NEW
                                               rollbackFor=DaoException.class)
                          public void work()
                          {
                              dao1.doStuff();
                              dao2.doStuff();
                          }
                      }

                      Comment


                      • #12
                        I really, don't know, where I am going wrong.
                        I created a class having my method with all the required dao calls and made as an aspect. calling the same method in another class. But still it is not doing the rollback. It is ignoring the failed one and going forward.
                        My daos are using hibernate. does this a bottleneck?

                        Comment


                        • #13
                          Originally posted by springTek View Post
                          I really, don't know, where I am going wrong.
                          I created a class having my method with all the required dao calls and made as an aspect. calling the same method in another class. But still it is not doing the rollback. It is ignoring the failed one and going forward.
                          My daos are using hibernate. does this a bottleneck?
                          Is the exception that you are throwing a subclass of RuntimeException?

                          Comment


                          • #14
                            Yes. my appexception is a subclass of Runtime Exception.

                            Comment


                            • #15
                              please supply sourcecode and appcontext.

                              Comment

                              Working...
                              X