Announcement Announcement Module
Collapse
No announcement yet.
How to make a non Spring Class part of a Transaction Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to make a non Spring Class part of a Transaction

    Hi,

    In my spring project, I'm using a class of "Interactive Brokers" and I explicitely annotate this class with @Component. This class is going to write into the DB via methods of a CRUDService (Spring bean), so I annotate all methods of the I.B. class with : @Transactional(propagation = Propagation.REQUIRES_NEW).

    PHP Code:
    @Component
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public class 
    RequestRealTimeBarsIB extends RetrievalBase {

        @
    Autowired
        
    private CRUDService crudService;

        @
    Transactional(propagation Propagation.REQUIRES_NEW)
        public 
    void realtimeBar(int reqIdlong timedouble opendouble highdouble lowdouble closelong volumedouble wapint count) {
              ...
              
    crudService.create(...);

    CRUDServiceBean.java


    PHP Code:
    @Repository
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    @
    Transactional(propagation Propagation.MANDATORY)
    // Above will simply ensure that a transaction has already been started when the DAO layer is entered
    public class CRUDServiceBean implements CRUDService {

        @
    PersistenceContext
        
    private EntityManager em;

        public 
    EntityManager getEntityManager() {
            return 
    em;
        }

        public <
    extends BaseEntityT create(T t) {
            
    em.persist(t);
            
    em.flush();
            
    em.refresh(t);
            return 
    t;
        } 

    The methods of RequestRealTimeBarsIB are called by Interactive brokers service automatically every 5 seconds.

    The Problem is that the create method of CRUDService is throwing an exception :
    HTML Code:
    "No Excisting transaction found for transaction marked with propagation 'mandatorry'
    How can I make sure that a transaction is started regardless how the method realtimeBar(..) is called ?

    Many thanks,

    Frank
    Last edited by fv967; Oct 11th, 2012, 03:36 PM.

  • #2
    Hi, you have several options here. If you don't have a control over creating instances of the class, you can use @Configurable annotation in combination with AspectJ weaving to register it as a Spring bean.
    If methods of the class call your Spring beans as you wrote and you want to encapsulate all the calls into a transaction, just wrap calls to the methods into a Spring bean on which you define transaction demarkation.
    If the methods don't use DB access via Spring, you can still wrap the calls into a Spring bean that creates a transaction (like in previous case) and use TransactionAwareDataSourceProxy to ensure all jdbc calls participate in the transaction.

    Comment


    • #3
      Hi,

      I've updated my question so it's better reflexing my problem. Could you please indicate what I've to do ? I'm quite new with spring.

      thanks, Frank

      Comment


      • #4
        From the exception string you have posted it is obvious that you have a transaction manager set up. I assume that you use <tx:annotation-driven />. Ensure that crudService.create(...) is called in the same thread as realTimeBar(...) (Spring transactions are bound to a thread). Next, make sure you have autocommit turned off on a data source. You can log debug messages on Spring JpaTransactionManager class to see if a transaction is created when realtimeBar is called (I assume you use JpaTransactionManager).

        >> The methods of RequestRealTimeBarsIB are called by Interactive brokers service automatically every 5 seconds.
        Who is reponsible for creating the instance of RequestRealTimeBarsIB? Is it injected somewhere or obtained by springContext.getBean()? It should be. In the previous version of your post I remember you wrote that the caller is not a Spring managed bean. Which one is it? (If RequestRealTimeBarsIB, how do you obtain CRUDService to it?)

        Another thing not related to the transaction problem - it is more common to use a singleton scope for beans that do not hold a state that differs among instances (at least CrudServiceBean in your case).

        Comment


        • #5
          Hi,

          Many thanks for your help !!!
          Yes, I've a transaction manager setup.
          The applicationcontext.xml

          PHP Code:
          <?xml version="1.0" encoding="UTF-8"?> 
                      
          <beans xmlns="http://www.springframework.org/schema/beans" 
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                 xmlns:tx="http://www.springframework.org/schema/tx" 
                 xmlns:context="http://www.springframework.org/schema/context" 
                 xmlns:task="http://www.springframework.org/schema/task" 
                 xsi:schemaLocation=" 
                     [url]http://www.springframework.org/schema/beans[/url]  
                     [url]http://www.springframework.org/schema/beans/spring-beans-3.0.xsd[/url] 
                     [url]http://www.springframework.org/schema/tx[/url]  
                     [url]http://www.springframework.org/schema/tx/spring-tx-3.0.xsd[/url] 
                     [url]http://www.springframework.org/schema/context[/url]  
                     [url]http://www.springframework.org/schema/context/spring-context-3.0.xsd[/url] 
                     [url]http://www.springframework.org/schema/task[/url]  
                     http://www.springframework.org/schema/task/spring-task-3.0.xsd">            
                      
              <context:component-scan base-package="com.stockdomain"> 
                  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
              </context:component-scan>     
               
              <bean id="contextApplicationContextProvider" class="com.stockdomain.util.ApplicationContextProvider"></bean>          

              <!-- dataSource --> 
              <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
                <property name="driverClassName"><value>org.postgresql.Driver</value></property> 
                <property name="url"><value>jdbc:postgresql://localhost/db_finance</value></property> 
                <property name="username"><value>xxxxx</value></property> 
                <property name="password"><value>xxxxx</value></property> 
              </bean>  
               
              <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
                  <property name="entityManagerFactory" ref="entityManagerFactory" /> 
              </bean>   

              <bean id="entityManagerFactory" 
                    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
                  <property name="persistenceUnitName" value="mypersistenceunit" /> 
                  <property name="dataSource" ref="dataSource" /> 
                  <property name="jpaVendorAdapter"> 
                      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
                          <property name="showSql" value="true" /> 
                          <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" /> 
                      </bean> 
                  </property> 
                  <property name="jpaPropertyMap"> 
                      <map> 
                          <entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> 
                      </map> 
                  </property> 
              </bean> 
                   
              <tx:annotation-driven transaction-manager="transactionManager"/>  
               
          </beans>

          Th
          e CRUDService.create(..) should be called in the same thread as realTimeBar(..).
          I'll double check that by logging debug messages on Spring JpaTransactionManager. (I hope I'll be able to manage that :-( ).

          The autocommit is turned off on my DB.

          Who is reponsible for creating the instance of RequestRealTimeBarsIB?
          RequestRealTimeBarsIB is autowired into a Controller. This Controller is calling a method "requestRealTimeBarsIB .eConnect()" . This makes is possible for the Interactive Brokers application to call realtimeBar(...) every 5 seconds.
          When I wrote that "the caller is not a Spring managed bean" , I meant the Interactive Brokers application (running as a separate apllication) which is calling realtimeBar(...) .

          I'll change the type of CRUDServiceBean, so that it becomes a singleton.

          Comment


          • #6
            I managed to log debug messages on Spring JpaTransactionManager. But, I don't get any debug messages for when the interactive brokers application is calling realtimeBar(...).
            This means that a because the IB application runs in a separate thread, no transaction is started ?

            How can I force the creation of a transaction ?

            Thanks, Frank

            Comment


            • #7
              >> But, I don't get any debug messages ...
              You should see any debug message at least when CRUDServiceBean#create() is called.

              >> This means that a because the IB application runs in a separate thread, no transaction is started ?
              Does it run in a separate thread? If you do not see any transaction debug log for create() method, your logging is propably not set up, because the exception you get is thrown from a method triggered from a transaction advice.
              There must be a reason why the transaction advice does not apply to the method you want. Does RequestRealTimeBarsIB implement any interface containing realtimeBar method? If not, jdk transaction proxy cannot be used. In this case, you should have cglib on your classpath, try <tx:annotation-driven proxy-target-class="true" /> to enforce cglib proxy creation style, realtimeBar should not be final.

              >> How can I force the creation of a transaction ?
              If you still won't manage the transaction to work using @Transactional, you can always control transactions manually by creating a bean of type TransactionalTemplate (configured with your transaction manager), inject it where you need it and use its execute(TransactionCallback) method.

              Comment


              • #8
                Sorry...I was using wrong words when referring to Lo messages. I do see log messages, but not messages indicating that a Transaction has been started.

                Comment


                • #9
                  Does RequestRealTimeBarsIB implement any interface containing realtimeBar method?
                  Yes, RequestRealTimeBarsIB extends from RetrievalBase and that class implements an interface wich contains realtimeBar(..).

                  Comment

                  Working...
                  X