Announcement Announcement Module
Collapse
No announcement yet.
Spring Transaction with simple JDBC. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Thanks Marten for efforts, but the project I am working is kind of big project and I cant share the code. But as you asked other question about right datasource in code. Here is the spring-config.xml where I have all bean definitions.
    Code:
            <bean id="proxyDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    		<property name="targetDataSource" ref="dataSource" />
    	</bean>
    	
    	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource"/>
    	</bean>
    	
    	<bean class="com.rest.common.RestUtil" name="CommonComponent">
          	<property name="serviceComponent">
             	<value>${component.name}</value>
          	</property>
    		<property name="defaultDataSource">
    			<ref bean="oracleRest" />
    		</property>
    	</bean>
    	
    	<bean name="oracleRest" class="com.rest.Oracle">
    		<property name="dataSource">
    			<ref bean="proxyDataSource" />
    		</property>
    		<property name="batchLimit">
    			<value>0</value>
    		</property>
    		<property name="writeDB">
    			<value>true</value>
    		</property>
    		<property name="schemaOwner">
    			<value>${schema}</value>
    		</property>
    	</bean>
    This is the same as I posted earlier and in Oracle class I am getting connection from the datasource as following.
    Code:
    -------Oracle Class
    public synchronized Connection getConnection() throws SQLException {
        if (!isCacheInitialized()) {
            initCacheRest();
        }
        
        long connectTime = System.currentTimeMillis();
    	Connection conn = DataSourceUtils.getConnection(getDataSource());
        
        if (conn == null) {
            throw new SQLException("No database connection is currently available. Please retry your request at a later time.");
        }
    
        try {    
    	    logger.debug("connection established in " + (System.currentTimeMillis()-connectTime) + "ms");
    	    if (mySchemaOwner != null && mySchemaOwner != "") {
    	        doSchemaChange = true;
    	        changeSchema(conn);
    	    }
    	    logger.debug("connection prepared in " + (System.currentTimeMillis()-connectTime) + "ms");
    	    return conn;
        } catch( SQLException e ) {
        	try {
        		conn.close();
        	} catch( SQLException e2) {
        		logger.warn(e2.getMessage());
        	}
        	
        	throw e;
        } catch( RuntimeException e ) {
        	try {
        		conn.close();
        	} catch( SQLException e2) {
        		logger.warn(e2.getMessage());
        	}
        	
        	throw e;
        }
    }
    And using this class I am getting connection and putting it in a RestUtil class's property RequestArgument Object and passing that Object to DAOs for Database operations.
    Code:
    -------ReatUtil class
    	public RequestArguments buildRequestArguments(String componentName) 
    		throws SQLException {
    		
    		Connection conn = null;
    		Oracle oracleToUse = null;
    		if( oracleToUse == null ) {
    			oracleToUse = myDefaultDataSource;
    		}
    		
    		if( logger.isDebugEnabled() ) {
    			logger.debug("Using oracle datasource for component: " + 
    					componentName + ", max connections=" +
    					", timeout=" +
    					oracleToUse.getDataSource().getLoginTimeout());
    		}
    		conn = oracleToUse.getConnection();
    		System.out.println(DataSourceUtils.isConnectionTransactional(conn, null));
    		
    		try {
    			RequestArguments requestArgs = 
    					(RequestArguments) myBeanFactory.getBean("RequestArgs");
    
    			requestArgs.setConnection(conn);
    			requestArgs.setComponent(componentName);
    
    			return requestArgs;
    		} catch( RuntimeException e ) {
    			if( conn != null ) {
    				try {
    					conn.close();
    				} catch( Exception e2 ) {
    					logger.warn("Could not close connection after " +
    							"exception occurred: " + e2.getMessage(), e2);
    				}
    			}
    			throw e;
    		}
    	}
    So here you can see I am printing that whether Connection is Transactional or not and tried manything and i always get false.
    And yes I have declared <tx:annotation-driven transaction-manager="transactionManager"/> in the app-config.xml which is taken as the context parameter when DispatcherServlet is loaded.

    if I am not wrong, I think either I am missing something in the spring-config.xml file or in the Oracle class where I am getting connection from the datasource.

    And I am very thankful that you put so effort for that.

    Thnx...

    Comment


    • #17
      I still think you are making it to complex .

      HOW are you passing things to the restutil and are you using the restutil from the spring configuration or do you simply construct a new one (making basically the one from the application context useless.

      So here you can see I am printing that whether Connection is Transactional or not and tried manything and i always get false.
      If you don't pass in a DataSource this method will always return false...

      Is it at least possible to send me the configuration and Oracle and RestUtil class and some (sample) code that uses the RestUtil class? (At least the configuration which contains the original datasaource, proxy, transaction manager and your oracle and restutil class.

      Comment


      • #18
        Hi Marten, I have attached the files you asked about. Please have a look and let me know the problem. Thnx....

        Comment


        • #19
          1) You are loading beans twice (and probably 3 times) so you end up with a whole lot of instances, datasources etc. etc.
          2) Your DispatcherServlet should load nothing and load all in the ContextLoaderListener
          3) Your startup servlet, WHY?! You can simply do all that in a xml file (or at least make it use the ContextLoaderListener)

          So you basically end up with different beans in different contexts, using different beans which don't know anything about each other....

          Also why do you have the 'ugly' singleton Components it it really needed I would simply configure it in the application context?

          Comment


          • #20
            Thanks Marten for your feedback. But I could not find, how am I loading beans more than one time, do you mean by passing app-config.xml as context-param and in DispatcherServlet. If don't give any init param in DispatcherServlet servlet it throws an error saying "java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/Service-servlet.xml]" and I never had this file. I think it looks for a config file if I don't define any in init param.
            How do I load beans using ContextLoaderListener?
            Your third point is right and I will do that and singleton class as well. But it would be great if you can tell me the bean loading part in more detail.

            Thanks

            Comment


            • #21
              Thanks Marten for your feedback. But I could not find, how am I loading beans more than one time, do you mean by passing app-config.xml as context-param and in DispatcherServlet. If don't give any init param in DispatcherServlet servlet it throws an error saying "java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/Service-servlet.xml]" and I never had this file. I think it looks for a config file if I don't define any in init param.
              The ContextLoaderListener and DispatcherServlet load the same xml file and as such load the same beans duplicating the configuration and even making it worse by using your startup servlet which has another set of beans. If you don't give a file it indeed throws an exception BUT you simply have to specify the parameter with no value.

              How do I load beans using ContextLoaderListener?
              You are already doing that (you have specified the ContextLoaderListener and specified which xml file to load).

              Comment


              • #22
                Hi Marten, I have done all the changes, but I am still having same problem. I am not able to get the transactional connection. I have attached the modified code. Please let me know where I am mistaken. Thanks.
                Last edited by springWSDev; Sep 7th, 2011, 03:21 AM.

                Comment


                • #23
                  I really don't get your code and still not have a clue what you are trying to do in that code (but that is probably my problem). Also why do you have that ugly class that has a BeanFactory which is initialized in some strange way... You shouldn't need that class that is why there is dependency injection! (Although that doesn't solve the problem).

                  So don't you get a connection (but an exception) or what? Is the code called from transactional code? What is the type of the connection you get back?

                  Comment


                  • #24
                    Hi Marten, I think this is going very long so if you could give me your email I would give you the whole idea what I am trying to do and why.

                    Thnx..

                    Comment


                    • #25
                      Hi,

                      As I explained in this thread, I am having problem in getting Connection which takes part in Transactions. For that I have application-Context.xml file with all beans needed.

                      Code:
                      	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                      		<property name="dataSource" ref="proxyDataSource"/>
                      	</bean>
                      	
                      	<bean id="proxyDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
                      		<property name="targetDataSource" ref="dataSource" />
                      	</bean>
                      Here I have customized Datasource

                      Code:
                      	<bean id="dataSource" class="com.dao.OracleDataSource">
                      		<property name="URL">
                      			<value>${datasource.url}</value>
                      		</property>
                      		<property name="user">
                      			<value>${datasource.user}</value>
                      		</property>
                      		<property name="password">
                      			<value>${datasource.password}</value>
                      		</property>
                      		<property name="useConnectionCache">
                      			<value>true</value>
                      		</property>
                      		<property name="minConnections">
                      			<value>${datasource.minConnections}</value>
                      		</property>
                      		<property name="maxConnections">
                      			<value>${datasource.maxConnections}</value>
                      		</property>
                      		<property name="initialConnections">
                      			<value>${datasource.initialConnections}</value>
                      		</property>
                      		<property name="loginTimeout">
                      			<value>5</value>
                      		</property>
                      		<property name="inactivityTimeout">
                      			<value>1800</value>
                      		</property>
                      		<property name="propertyCheckInterval">
                      			<value>900</value>
                      		</property>
                      	</bean>
                      In my old code we have a handler which connect to the DAOs for the database operations. First I get the Connection form the above Datasource and then set autoCommit to False. After getting the Connection I will pass that to DAOs which are the legacy code. Those DAOs use that in creation of different type of SQL Statements. Which will update database. After execution of different operations of DAOs it looks for exception and if it gets any it rollbacks otherwise commits the connection.

                      But now we have different service which needs to be take part in Transaction so now Service layer will call DAOs with passing the Connection to DAOs. And at the end it should rollback or commit accordingly.

                      I have @Transactional annotation on Service methods.

                      Code:
                      	@Transactional
                      	public void  addGenericDocument(AddDocument input, String user, String password) {
                      		//Get connection ?
                      		//Call number of DAOs operations by passing Connection
                      	}
                      The only thing I am not getting is how would I get the Connection and make it transactional and pass it to the DAOs.

                      Comment


                      • #26
                        The only thing I am not getting is how would I get the Connection and make it transactional and pass it to the DAOs.
                        You should simply get the connection it should already be transactional... If it isn't your @Transactional is useless.... What you can do it simply inject the TransactionAwareDataSourceProxy as the datasource, call getConnection in your transactional method and that should be it. Make sure you have tx:annotation-driven and that you use the correct proxies instance (which should be the case if you don't duplicate component-scan and don't duplicate loading of configuration). What you can do is throw a runtime exception in the method and post the stack trace. There should be a TransactionInterceptor somewhere in that stack trace, if it isn't your transactions are configured wrong.

                        Also make sure that you use the TransactionAwareDataSourceProxy every where where you want a DataSource and not the plain datasource...

                        Comment

                        Working...
                        X