Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: JpaTransactionManager freezes

  1. #1
    Join Date
    Jan 2007
    Posts
    28

    Default JpaTransactionManager freezes

    Greetings,

    I'm facing with the strange issue happening while unit-testing my Spring\JPA application: test-suite freezes after showing the following message in log4j output

    (AbstractTransactionalSpringContextTests.java:318) INFO com.trilogy.dm.DMRemoteTest - Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@ 174a6e2]; default rollback = true

    In short, my application has data access layer, which I test separately using the example from http://blog.springframework.com/markf/ - everything works just fine. Now I want to perform more advanced testing that involves obtaining the remote service reference and invoking remote methods locally (in unit test code). Since the test methods will be the same (the only change is the mechanism of getting the reference to a service: in initial test is was constructed locally, now I want it to be constructed on the server-side and be transferred to a client side by Hessian). So I subclassed my initial test class in hope that mere changing of spring configuration will do the job.


    Here is my initial test config:
    Code:
    <bean id="dmService"
    		class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
    		<property name="serviceUrl">
    			<value>http://localhost:8080/dmService/dm.service</value>
    		</property>
    		<property name="serviceInterface">
    			<value>com.foo.dm.IDMService</value>
    		</property>
    	</bean>
    But here the problems started... First, Spring gave me complaints about unsatisfied dependencies like "dataSource", "entityManagerFactory" and "transactionManager". I figured out that these beans are in Spring Test hierarchy and are used to fill database with test data. Pretty fare, I do need somehow initialize them. So I copy\pasted these beans definitions from my server-side spring config:

    Code:
    <bean id="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName"
    			value="net.sourceforge.jtds.jdbc.Driver" />
    		<property name="url"
    			value="jdbc:jtds:sqlserver://localhost/Database111" />
    		<property name="username" value="sa" />
    		<property name="password" value="sa" />
    	</bean>
    
    	<bean id="entityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="jpaVendorAdapter">
    			<bean
    				class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    				<property name="showSql" value="true" />
    				<property name="generateDdl" value="false" />
    				<property name="database" value="SQL_SERVER"/>
    			</bean>
    		</property>
    	</bean>
    
    
    	<bean id="transactionManager"
    		class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory"
    			ref="entityManagerFactory" />
    		<property name="dataSource" ref="dataSource" />
    	</bean>

    Ok, now seems that my tests have all required setup to execute smoothly. But here comes my main problem. The test suite launches, jdbcTemplate fills database with data and then.... nothing happens. I mean, test suite freezes... The last message in log4j is quoted in the beginning of the post.

    My guess is that local TransactionManager somehow conflicts with the server-side one, causing some kind of deadlock. Is it possible?


    Can someone point me to what I'm doing wrong? Maybe I should provide some additional info? Any pointers\suggestions will be greatly appreciated!

    Thanks in advance for all responses!

  2. #2
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    I'm not 100% sure, but it does sound like you've deadlocked on something. If you suspend the threads in eclipse (or whatever you use) you should be able to track the deadlock down.

    If your unit testing something that has nothing to do with databases, entityManagers etc..... then do you still need to extend the same Spring unit test case? I would have thought there would be a better option here. Also if you split your applicationContext.xml files up, you can only load the beans you need for the unit tests.
    Last edited by karldmoore; Jan 9th, 2007 at 01:57 PM.

  3. #3
    Join Date
    Jan 2007
    Posts
    28

    Default

    Quote Originally Posted by karldmoore View Post
    I'm not 100% sure, but it does sound like you've deadlocked on something. If you suspend the threads in eclipse (or whatever you use) you should be able to track the deadlock down.

    If your unit testing something that has nothing to do with databases, entityManagers etc..... then do you still need to extend the same Spring unit test case? I would have thought there would be a better option here. Also if you split your applicationContext.xml files up, you can only load the beans you need for the unit tests.
    Well, the thing is that I'm trying to test the same persistence operations but using remote calls, i.e. to make in-container tests. That's why I still extend Spring test case: I need jdbcTemplate to populate the database tables, DataSource to point to the DB and so on...

    Anyway, thanks for the suggestion!

  4. #4
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    Quote Originally Posted by sonar-ua View Post
    Well, the thing is that I'm trying to test the same persistence operations but using remote calls, i.e. to make in-container tests. That's why I still extend Spring test case: I need jdbcTemplate to populate the database tables, DataSource to point to the DB and so on...

    Anyway, thanks for the suggestion!
    OK, is it possible to see the applicationContext.xml and the test you are running?

  5. #5
    Join Date
    Jan 2007
    Posts
    28

    Default

    I actually have two app configs - server one and client one. Here they are:

    server-config.xml
    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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
    
        <!-- =============  -->
        <!-- Service Beans  -->
        <!-- =============  -->
        
    	<bean id="oaService"
    		class="com.trilogy.orderagent.OrderAgentServiceImpl">
    		<property name="entityManagerFactory">
    			<ref bean="entityManagerFactory" />
    		</property>
    	</bean>
    
    
    
        <!-- ================  -->
        <!-- Remote Exporters  -->
        <!-- ================  -->
    	<bean name="hessianOaService" class="org.springframework.remoting.caucho.HessianServiceExporter">
    		<property name="service">
    			<ref bean="oaService"/>
    		</property>
    		<property name="serviceInterface">
    			<value>com.package1.IOAService</value>
    		</property>
    	</bean>
    
    
        
        
        <!-- ================  -->
        <!--   URL Mapping     -->
        <!-- ================  -->
    	<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    		<property name="mappings">
    		<props>
    			<prop key="/oa.service">hessianOaService</prop>
    		</props>
    		</property>
    	</bean>
    
    
        <!-- =========================  -->
        <!-- Spring Bridge with JPA     -->
        <!-- =========================  -->
        
    	<bean id="entityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="jpaVendorAdapter">
    			<bean
    				class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    				<property name="showSql" value="true" />
    				<property name="generateDdl" value="false" />
    				<property name="database" value="SQL_SERVER"/>
    			</bean>
    		</property>
    	</bean>
    
    
        <!-- ======================================================  -->
        <!-- Datasource Declaration -->
        <!-- ======================================================  -->
    	<bean id="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName"
    			value="net.sourceforge.jtds.jdbc.Driver" />
    		<property name="url"
    			value="jdbc:jtds:sqlserver://localhost/NewDB" />
    		<property name="username" value="sa" />
    		<property name="password" value="sa" />
    	</bean>
    
    
        <!-- =========================  -->
        <!-- Transaction Manager        -->
        <!-- =========================  -->
    	<bean id="transactionManager"
    		class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory"
    			ref="entityManagerFactory" />
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    
    </beans>
    client-config.xml
    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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
    	<bean id="oaService"
    		class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
    		<property name="serviceUrl">
    			<value>http://localhost:8080/oaService/oa.service</value>
    		</property>
    		<property name="serviceInterface">
    			<value>com.package1.IOAService</value>
    		</property>
    	</bean>
    
    
    
        <!-- ======================================================  -->
        <!-- Datasource Declaration -->
        <!-- ======================================================  -->
    	<bean id="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName"
    			value="net.sourceforge.jtds.jdbc.Driver" />
    		<property name="url"
    			value="jdbc:jtds:sqlserver://localhost/NewDB" />
    		<property name="username" value="sa" />
    		<property name="password" value="sa" />
    	</bean>
    
    
        <!-- =========================  -->
        <!-- Spring Bridge with JPA     -->
        <!-- =========================  -->
        
    	<bean id="entityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="jpaVendorAdapter">
    			<bean
    				class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    				<property name="showSql" value="true" />
    				<property name="generateDdl" value="false" />
    				<property name="database" value="SQL_SERVER"/>
    			</bean>
    		</property>
    	</bean>
    
    
        <!-- =========================  -->
        <!-- Transaction Manager        -->
        <!-- =========================  -->
    	<bean id="transactionManager"
    		class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory"
    			ref="entityManagerFactory" />
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    
    </beans>

    The test code is quite trivial:
    Code:
    	
    public class MiscTests extends AbstractJpaTests
    {
    
    	private IOAService oaService;	
    	
    	public void setOaService(IOAService oaService) 
            {
    		this.oaService = oaService;
    	}
    
    	protected String[] getConfigLocations() 
    	{
    	    return new String[] {"classpath:/client-test.xml"};
    	}
    
    	protected void onSetUpInTransaction() throws Exception 
    	{
                    //prepare test database structure 
    		jdbcTemplate.execute(.....);
             }
    
    
            public void testGetUser() throws Exception
    	{
    		String username = "John_Doe_login";
    		String password = "password_test";
    		Dosuser user = oaService.getUser(username, password); 
    		assertNotNull(user);
    		assertEquals(1000, user.getUserKey());
    		assertEquals(4, user.getDealers().size()); //this user has 4 dealers 
    	}

    As you can see, my client config file is set up for obtaining a reference to IOAService via Spring Remote mechanism (Hessian in this case) and Spring is also responsible for injecting this reference into my unit test class MiscTests. This works just fine. The server-side code berofe running the test suite is properly deployed into a servlet container (Tomcat), which is up and running.

    What is NOT working (for now) is my unit test method testGetUser() which freezes somewhere inside oaService.getUser(username, password) (or after) I guess that the database IS being hit, because in the Tomcat console I can see SQL for the operation:

    Code:
    Hibernate:
        select
            alias0_.UserName as UserName1_,
            alias0_.UserKey as UserKey1_
        from
            NewDB.dbo.Alias alias0_
        where
            alias0_.UserName=?
    Why the application flow freezes after that is a mystery for me. Hope this information will help someone to point me to what I'm doing wrong here.

  6. #6
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    As I said previously, if you suspend the threads in eclipse (or whatever you use) you should be able to track the deadlock down.

    I'm slightly puzzled however, you said there was a message that talked about DMRemoteTest starting a transaction. I can't see this class in your configuration.

  7. #7
    Join Date
    Jan 2007
    Posts
    28

    Default

    I've tried that! Let me show you the link to a screenshot of one of the suspended threads. It seems that jdbc driver waits for something. Can you please comment on this?

    here is the screenshot: http://keep4u.ru/full/070110/05a4f5e65c49e843bd/jpg

  8. #8
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    It does look like its deadlocked. What does the jdbcTemplate do in the onSetUpInTransaction method? It might also be worth looking at the NotTransactional annotation to see if that helps.

    Test methods can be annotated with the regular Spring Transactional annotation (for example, to force execution in a read-only transaction) or with the NotTransactional annotation to prevent any transaction being created at all.
    http://www.springframework.org/docs/...tJpaTests.html
    Last edited by karldmoore; Jan 10th, 2007 at 06:42 AM.

  9. #9
    Join Date
    Jan 2007
    Posts
    28

    Default

    Basically, jdbcTemplate puts some test data into database. So its critical for the test methods to be executed in transaction. If I use @NotTransactional annotation, all tests fail because they rely on the existent database content.

    Maybe you have some other suggestion? Thanks in advance!

  10. #10
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    I don't really know what to say. The SQL that comes out names 'NewDB.dbo.Alias' as the table its trying to read. I would assume this is your problem, as to why it's locked it I'm not sure. Is it possible to see that SQL?

    When I was talking about NotTransactional I actually meant the test method, testGetUser.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •