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

Thread: hibernate.hbm2ddl.auto=create-drop feature KO with Junit

  1. #1
    Join Date
    Dec 2005
    Location
    paris
    Posts
    13

    Default hibernate.hbm2ddl.auto=create-drop feature KO with Junit

    I try to setup junit test with spring 1.2.6 and hibernate 3.05.
    When the test ends up, it should drop the whole schema because hbm2ddl.auto=create-drop is set: shouldn't it ?

    i can't figure out why the schema is still existing !!

    The schema is created at applicationContext creation in the setup method.
    The schema should be deleted at applicationContext closing: How is it closed (no API available) ?

    here is my config file:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    
    <beans>
    	<bean id="gestionnaireTache"
    		class="coach.service.impl.basic.GestionnaireTache">
    	</bean>
    	<bean id="gestionnaireRessource"
    		class="coach.service.impl.basic.GestionnaireRessource">
    	</bean>
    	<bean id="coachFactory"
    		class="coach.model.impl.basic.ModelBasicFactory">
    		<property name="gestionnaireRessource">
    			<ref bean="gestionnaireRessource" />
    		</property>
    		<property name="gestionnaireTache">
    			<ref bean="gestionnaireTache" />
    		</property>
    	</bean>
    
    	<!-- Permet de maintenir les parametres hibernate dans un fichier properties -->
    	<bean id="placeholderConfig"
    		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    		<property name="location">
    			<value>/hibernate.properties</value>
    		</property>
    	</bean>
    
    	<!-- DataSource defintion -->
    	<bean id="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName">
    			<value>${hibernate.connection.driver_class}</value>
    		</property>
    		<property name="url">
    			<value>${hibernate.connection.url}</value>
    		</property>
    		<property name="username">
    			<value>${hibernate.connection.username}</value>
    		</property>
    		<property name="password">
    			<value>${hibernate.connection.password}</value>
    		</property>
    	</bean>
    
    	<!-- Session factory pour Hibernate -->
    	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="mappingDirectoryLocations">
    			<value>classpath*:coach/model/impl/basic</value>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">
    					${hibernate.dialect}
    				</prop>
    				<prop key="hibernate.show_sql">
    					${hibernate.show_sql}
    				</prop>
    				<prop key="hibernate.max_fetch_depth">
    					${hibernate.max_fetch_depth}
    				</prop>
    				<prop key="hibernate.hbm2ddl.auto">
    					${hibernate.hbm2ddl.auto}
    				</prop>
    				<prop key="hibernate.cache.provider_class">
    					${hibernate.cache.provider_class}
    				</prop>
    			</props>
    		</property>
    		<property name="dataSource">
    			<ref bean="dataSource" />
    		</property>
    	</bean>
    
    	<!-- Gestionnaire de transaction pour Hibernate -->
    	<bean id="transactionManager"
    		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory">
    			<ref bean="sessionFactory" />
    		</property>
    	</bean>
    
    	<!-- DAO pour la gestion des Unites -->
    	<bean id="uniteDaoTarget"
    		class="coach.dao.impl.hibernate.UniteDao">
    		<property name="sessionFactory">
    			<ref local="sessionFactory" />
    		</property>
    	</bean>
    
    	<bean id="txProxyTemplate" abstract="true"
    		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    		<property name="transactionManager" ref="transactionManager" />
    		<property name="transactionAttributes">
    			<props>
    				<prop key="*">PROPAGATION_REQUIRED</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="uniteDaoProxy" parent="txProxyTemplate">
    		<property name="target">
    			<ref bean="uniteDaoTarget" />
    		</property>
    	</bean>
    
    </beans>
    Here is my junit test:

    Code:
    package coach.dao.impl.hibernate;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import coach.dao.UniteDAOIF;
    import coach.model.UniteIF;
    import coach.model.impl.basic.ModelBasicFactory;
    import coach.model.impl.basic.Unite;
    
    import junit.framework.TestCase;
    
    public class UniteDaoSpringTest extends TestCase {
    
    	ModelBasicFactory mvf;
    	ApplicationContext apc;
    	UniteDAOIF uniteDao;
    
    	protected void setUp() throws Exception {
    		super.setUp();
    		//C'est à la création du context que le schema est crée.
    		apc = new ClassPathXmlApplicationContext("coach/applicationContext.xml");
    		mvf = (ModelBasicFactory)apc.getBean("coachFactory");
    		uniteDao = (UniteDAOIF)apc.getBean("uniteDaoTarget");
    	}
    	
    	protected void tearDown() throws Exception {
    		super.tearDown();
    		//Comment faire pour dropper le schema de la base ??
    		//Il faudrait normalement fermer le context spring qui 
    		//fermerait à son tour la sessionfactory hibernate
    	}	
    
    	public void testUniteCreateHibernateSpring() throws Throwable {
    		UniteIF unJourHomme = mvf.getJourHomme();
    		Long id = uniteDao.create(unJourHomme);
    		UniteIF unJourHommeRes = (UniteIF)uniteDao.find(id);
    		assertEquals(((Unite)unJourHomme).getId(), ((Unite)unJourHommeRes).getId());
    	}
    	
    	public void testUniteDelete() throws Throwable {
    		UniteIF unJourHomme = mvf.getJourHomme();
    		uniteDao.create(unJourHomme);
    		uniteDao.delete(unJourHomme);
    		uniteDao.close();
    		assertNull(uniteDao.find(((Unite)unJourHomme).getId()));
    	}	
    }

  2. #2
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    hbm2ddl.auto=create-drop is set: shouldn't it ?
    I'm not sure about that - the HB forums can provide more answers to that. However, when doing integration tests (w/ a database) Spring provides some really nice tests which are aware of your context and actually start a transaction for the scope of the tests so at the end, the transaction is rolled back and the changes are not persisted. This is not just convenient it's also very fast.
    However, when doing DDL changes some database (including MySQL) do not include that inside the transaction scope - that is, if you drop a table rolling back the transaction will not un-drop the table.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  3. #3
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    Check the Test package from Spring distribution (namely AbstractTransactionalSpringContextTests).
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  4. #4
    Join Date
    Dec 2005
    Location
    paris
    Posts
    13

    Default Thanks Costin

    I have already check the test package and it nicely rolls back all the data. But it doesn't drop the schema; that'as the only problem.
    I can't understand why, and more over i don't understand why the applicationContext doesn't provide a close method.

    here is my code with the test package:

    Code:
    package coach.dao.impl.hibernate;
    
    import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
    
    import coach.dao.UniteDAOIF;
    import coach.exception.CoachDaoException;
    import coach.model.UniteIF;
    import coach.model.impl.basic.ModelBasicFactory;
    import coach.model.impl.basic.Unite;
    
    public class UniteDaoSpringContextTest extends AbstractTransactionalDataSourceSpringContextTests {
    	
    	ModelBasicFactory mvf;
    	UniteDAOIF uniteDao;
    	
    	protected String[] getConfigLocations() {
    		return new String[] {"classpath:/coach/applicationContext.xml"};
    	}
    	
    	protected void onSetUpBeforeTransaction() throws Exception {
    		mvf = (ModelBasicFactory)applicationContext.getBean("coachFactory");
    		uniteDao = (UniteDAOIF)applicationContext.getBean("uniteDaoTarget");
    	}
    	
    	protected void onTearDownAfterTransaction() throws Exception {
    		super.onTearDownAfterTransaction();
    		//Comment faire pour dropper le schema de la base ??
    		//Il faudrait normalement fermer le context spring qui 
    		//fermerait à son tour la sessionfactory hibernate
    	}
    
    	public void testUniteCreate() throws Throwable {
    		UniteIF unJourHomme = mvf.getJourHomme();
    		Long id = uniteDao.create(unJourHomme);
    		UniteIF unJourHommeRes = (UniteIF)uniteDao.find(id);
    		assertEquals(((Unite)unJourHomme).getId(), ((Unite)unJourHommeRes).getId());
    	}	
    	
    	public void testUniteDelete() throws Throwable {
    		UniteIF unJourHomme = mvf.getJourHomme();
    		uniteDao.create(unJourHomme);
    		uniteDao.delete(unJourHomme);
    		try {
    			uniteDao.find(((Unite)unJourHomme).getId());
    		} catch (CoachDaoException cde) {
    			assertTrue(true);
    		}
    	}	
    }

  5. #5
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    AbstractApplicationContext does have a close method - use that to drop the schema manually. Again, check that HB indeed can drop the database and find out why it does not happen.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  6. #6
    Join Date
    Dec 2005
    Location
    paris
    Posts
    13

    Default Thanks Costin

    Right, the context have a close method but, when i manually call it i get an exception at hibernate schema export step:

    i have written a very simple unit test case that fails:

    Code:
    package coach.service.impl.basic;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import junit.framework.TestCase;
    
    public class HibernateSchemaExport extends TestCase {
    	
    	ClassPathXmlApplicationContext apc;
    	
    	protected void setUp() throws Exception {
    		super.setUp();
    		apc = new ClassPathXmlApplicationContext("coach/applicationContext.xml");
    	}
    	
    	protected void tearDown() throws Exception {
    		super.tearDown();	
    	}
    	
    	public void testApcClose() {
    		apc.close();
    	}
    }
    the stack trace clearly points out that HB tries to drop the schema (when it calls <Running hbm2ddl schema export>)

    Code:
    2005-12-19 19:18:33,054 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Retrieving dependent beans for bean 'userDao'>
    2005-12-19 19:18:33,054 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Invoking destroy() on bean with name 'sessionFactory'>
    2005-12-19 19:18:33,054 INFO [org.springframework.orm.hibernate3.LocalSessionFactoryBean] - <Closing Hibernate SessionFactory>
    2005-12-19 19:18:33,054 INFO [org.hibernate.impl.SessionFactoryImpl] - <closing>
    2005-12-19 19:18:33,054 INFO [org.hibernate.tool.hbm2ddl.SchemaExport] - <Running hbm2ddl schema export>
    2005-12-19 19:18:33,054 INFO [org.hibernate.tool.hbm2ddl.SchemaExport] - <exporting generated schema to database>
    2005-12-19 19:18:33,054 INFO [org.hibernate.connection.ConnectionProviderFactory] - <Initializing connection provider: org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider>
    2005-12-19 19:18:33,054 ERROR [org.hibernate.tool.hbm2ddl.SchemaExport] - <schema export unsuccessful>
    org.hibernate.HibernateException: No local DataSource found for configuration - dataSource property must be set on LocalSessionFactoryBean
    	at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.configure(LocalDataSourceConnectionProvider.java:48)
    	at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:80)
    	at org.hibernate.tool.hbm2ddl.SchemaExport$ProviderConnectionHelper.getConnection(SchemaExport.java:431)
    	at org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:130)
    	at org.hibernate.tool.hbm2ddl.SchemaExport.drop(SchemaExport.java:108)
    	at org.hibernate.impl.SessionFactoryImpl.close(SessionFactoryImpl.java:812)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    	at java.lang.reflect.Method.invoke(Unknown Source)
    	at org.springframework.orm.hibernate3.LocalSessionFactoryBean$TransactionAwareInvocationHandler.invoke(LocalSessionFactoryBean.java:1021)
    	at $Proxy0.close(Unknown Source)
    	at org.springframework.orm.hibernate3.LocalSessionFactoryBean.destroy(LocalSessionFactoryBean.java:982)
    	at org.springframework.beans.factory.support.AbstractBeanFactory$1.destroy(AbstractBeanFactory.java:923)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.destroyBean(AbstractBeanFactory.java:1014)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.destroyDisposableBean(AbstractBeanFactory.java:986)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.destroySingletons(AbstractBeanFactory.java:557)
    	at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:530)
    	at coach.service.impl.basic.HibernateSchemaExport.testApcClose(HibernateSchemaExport.java:21)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    	at java.lang.reflect.Method.invoke(Unknown Source)
    	at junit.framework.TestCase.runTest(TestCase.java:154)
    	at junit.framework.TestCase.runBare(TestCase.java:127)
    	at junit.framework.TestResult$1.protect(TestResult.java:106)
    	at junit.framework.TestResult.runProtected(TestResult.java:124)
    	at junit.framework.TestResult.run(TestResult.java:109)
    	at junit.framework.TestCase.run(TestCase.java:118)
    	at junit.framework.TestSuite.runTest(TestSuite.java:208)
    	at junit.framework.TestSuite.run(TestSuite.java:203)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
    My config file wires the dataSource bean to the LocalSessionFactory, but Spring closes it too much soon, don't you think ??

    here is my config file:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    
    <beans>
    	<!-- Permet de maintenir les parametres hibernate dans un fichier properties -->
    	<bean id="placeholderConfig1"
    		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    		<property name="location">
    			<value>/hibernate.properties</value>
    		</property>
    	</bean>
    
    	<!-- DataSource defintion -->
    	<bean id="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName">
    			<value>${hibernate.connection.driver_class}</value>
    		</property>
    		<property name="url">
    			<value>${hibernate.connection.url}</value>
    		</property>
    		<property name="username">
    			<value>${hibernate.connection.username}</value>
    		</property>
    		<property name="password">
    			<value>${hibernate.connection.password}</value>
    		</property>
    	</bean>
    
    	<!-- Session factory pour Hibernate -->
    	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="mappingDirectoryLocations">
    			<value>classpath*:coach/model/impl/basic</value>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">
    					${hibernate.dialect}
    				</prop>
    				<prop key="hibernate.show_sql">
    					${hibernate.show_sql}
    				</prop>
    				<prop key="hibernate.max_fetch_depth">
    					${hibernate.max_fetch_depth}
    				</prop>
    				<prop key="hibernate.hbm2ddl.auto">
    					${hibernate.hbm2ddl.auto}
    				</prop>
    				<prop key="hibernate.cache.provider_class">
    					${hibernate.cache.provider_class}
    				</prop>
    			</props>
    		</property>
    		<property name="dataSource">
    			<ref local="dataSource" />
    		</property>
    	</bean>
    
    	<!-- Gestionnaire de transaction pour Hibernate -->
    	<bean id="transactionManager"
    		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory">
    			<ref bean="sessionFactory" />
    		</property>
    	</bean>
    
    	<!-- DAO pour la gestion des Unites -->
    	<bean id="uniteDao" class="coach.dao.impl.hibernate.UniteDao">
    		<property name="sessionFactory">
    			<ref local="sessionFactory" />
    		</property>
    	</bean>
    	<!-- DAO pour la gestion des Configuration -->
    	<bean id="configurationDao"
    		class="coach.dao.impl.hibernate.ConfigurationDao">
    		<property name="sessionFactory">
    			<ref local="sessionFactory" />
    		</property>
    	</bean>
    	<!-- DAO pour la gestion des user -->
    	<bean id="userDao" class="coach.dao.impl.hibernate.UserDao">
    		<property name="sessionFactory">
    			<ref local="sessionFactory" />
    		</property>
    	</bean>
    
    	<!-- Service de creation des objets du model -->
    	<bean id="coachModelFactory"
    		class="coach.model.impl.basic.ModelBasicFactory">
    	</bean>
    	<!-- Service de gestion des taches -->
    	<bean id="gestionnaireTacheTarget"
    		class="coach.service.impl.basic.GestionnaireTache">
    	</bean>
    	<!-- Service de gestion des ressources -->
    	<bean id="gestionnaireRessourceTarget"
    		class="coach.service.impl.basic.GestionnaireRessource">
    	</bean>
    	<!-- Service de gestion des configurations -->
    	<bean id="gestionnaireConfigurationTarget"
    		class="coach.service.impl.basic.GestionnaireConfiguration">
    		<property name="configurationDao">
    			<ref local="configurationDao" />
    		</property>		
    	</bean>
    
    	<!-- Service d'init -->
    	<bean id="initServiceTarget"
    		class="coach.service.impl.basic.InitService">
    		<property name="availableServices">
    			<map>
    				<entry>
    					<key>
    						<value>gestionnaireTacheTarget</value>
    					</key>
    					<ref bean="gestionnaireTacheTarget" />
    				</entry>
    				<entry>
    					<key>
    						<value>gestionnaireRessourceTarget</value>
    					</key>
    					<ref bean="gestionnaireRessourceTarget" />
    				</entry>
    				<entry>
    					<key>
    						<value>gestionnaireConfigurationTarget</value>
    					</key>
    					<ref bean="gestionnaireConfigurationTarget" />
    				</entry>
    			</map>
    		</property>
    		<property name="coachModelFactory">
    			<ref bean="coachModelFactory" />
    		</property>
    	</bean>
    
    	<bean id="txProxyTemplate" abstract="true"
    		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    		<property name="transactionManager" ref="transactionManager" />
    		<property name="transactionAttributes">
    			<props>
    				<prop key="*">PROPAGATION_REQUIRED</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="gestionnaireConfigurationProxy"
    		parent="txProxyTemplate">
    		<property name="target">
    			<ref bean="gestionnaireConfigurationTarget" />
    		</property>
    	</bean>
    
    </beans>

  7. #7
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    Yes, appearently it does. I think you should raise an issue on JIRA - obviously the LocalSessionFactoryBean should be the one started and then it's dependencies.
    I guess a very quick 'hack' would be to manually turn off the factory at the end of your test and only after that do a appContext.close().
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  8. #8
    Join Date
    Dec 2005
    Location
    paris
    Posts
    13

    Default Ok, thanks Costin

    Quote Originally Posted by costin
    Yes, appearently it does. I think you should raise an issue on JIRA - obviously the LocalSessionFactoryBean should be the one started and then it's dependencies.
    I guess a very quick 'hack' would be to manually turn off the factory at the end of your test and only after that do a appContext.close().

    What do you mean by "turn off the factory" ? can you give me a sample code ?


    I created the SPR-1547 on JIRA....

    Thank you for your help
    Last edited by dsissoko; Dec 19th, 2005 at 02:22 PM.

  9. #9
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    I meant destorying the factory youtself. Take a look at the LocalSessionFactoryBean and see what happens inside the destroy method. You can also get a hold of the Factory itself (the LocalSessionFactoryBean that is) by querying the application context for &sessionFactory, i.e.:

    Code:
    appContext.getBean("&sessionFactory");
    and then calling destroy on it.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  10. #10
    Join Date
    Dec 2005
    Location
    paris
    Posts
    13

    Default SPR-1547: the bug created for this issue is fixed

    Fix Version: 2.0 M1

Posting Permissions

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