[SPR-5699] Investigating issues surrounding automatic flushing of the underlying ORM tool's session via TransactionalTestExecutionListener.

This commit is contained in:
Sam Brannen 2009-07-11 16:45:48 +00:00
parent c519f2bd3a
commit 29327798c1
14 changed files with 515 additions and 5 deletions

View File

@ -27,6 +27,10 @@
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.2.RELEASE/com.springsource.org.aspectj.weaver-1.6.2.RELEASE.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.el/com.springsource.javax.el/1.0.0/com.springsource.javax.el-1.0.0.jar" sourcepath="/IVY_CACHE/javax.el/com.springsource.javax.el/1.0.0/com.springsource.javax.el-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.collections/3.2.0/com.springsource.org.apache.commons.collections-3.2.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.collections/3.2.0/com.springsource.org.apache.commons.collections-sources-3.2.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.hibernate/com.springsource.org.hibernate/3.3.1.GA/com.springsource.org.hibernate-3.3.1.GA.jar" sourcepath="/IVY_CACHE/org.hibernate/com.springsource.org.hibernate/3.3.1.GA/com.springsource.org.hibernate-sources-3.3.1.GA.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.hsqldb/com.springsource.org.hsqldb/1.8.0.9/com.springsource.org.hsqldb-1.8.0.9.jar" sourcepath="/IVY_CACHE/org.hsqldb/com.springsource.org.hsqldb/1.8.0.9/com.springsource.org.hsqldb-sources-1.8.0.9.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.slf4j/com.springsource.slf4j.api/1.5.3/com.springsource.slf4j.api-1.5.3.jar" sourcepath="/IVY_CACHE/org.slf4j/com.springsource.slf4j.api/1.5.3/com.springsource.slf4j.api-sources-1.5.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.slf4j/com.springsource.slf4j.jcl/1.5.3/com.springsource.slf4j.jcl-1.5.3.jar" sourcepath="/IVY_CACHE/org.slf4j/com.springsource.slf4j.jcl/1.5.3/com.springsource.slf4j.jcl-sources-1.5.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.antlr/com.springsource.antlr/2.7.6/com.springsource.antlr-2.7.6.jar" sourcepath="/IVY_CACHE/org.antlr/com.springsource.antlr/2.7.6/com.springsource.antlr-sources-2.7.6.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -25,12 +25,15 @@
<dependency org="javax.portlet" name="com.springsource.javax.portlet" rev="2.0.0" conf="provided->compile"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet" rev="2.5.0" conf="provided->compile"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp" rev="2.1.0" conf="provided->compile"/>
<dependency org="org.junit" name="com.springsource.junit" rev="3.8.2" conf="optional->compile"/>
<dependency org="org.junit" name="com.springsource.org.junit" rev="4.6.0" conf="optional->compile"/>
<dependency org="javax.transaction" name="com.springsource.javax.transaction" rev="1.1.0" conf="provided->compile"/>
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile->compile"/>
<dependency org="org.apache.taglibs" name="com.springsource.org.apache.taglibs.standard" rev="1.1.2" conf="optional->compile"/>
<dependency org="org.aspectj" name="com.springsource.org.aspectj.weaver" rev="1.6.3.RELEASE" conf="optional->compile"/>
<dependency org="org.testng" name="com.springsource.org.testng" rev="5.9.0" conf="optional->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.3.1.GA" conf="test->compile"/>
<dependency org="org.hsqldb" name="com.springsource.org.hsqldb" rev="1.8.0.9" conf="test->compile"/>
<dependency org="org.junit" name="com.springsource.junit" rev="3.8.2" conf="optional->compile"/>
<dependency org="org.junit" name="com.springsource.org.junit" rev="4.6.0" conf="optional->compile"/>
<dependency org="org.slf4j" name="com.springsource.slf4j.jcl" rev="1.5.3" conf="test->compile"/>
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="optional->compile"/>
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="optional->compile"/>
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="optional->compile"/>
@ -41,7 +44,7 @@
<dependency org="org.springframework" name="org.springframework.web" rev="latest.integration" conf="optional->compile"/>
<dependency org="org.springframework" name="org.springframework.web.portlet" rev="latest.integration" conf="optional->compile"/>
<dependency org="org.springframework" name="org.springframework.web.servlet" rev="latest.integration" conf="optional->compile"/>
<dependency org="org.hsqldb" name="com.springsource.org.hsqldb" rev="1.8.0.9" conf="test->compile"/>
<dependency org="org.testng" name="com.springsource.org.testng" rev="5.9.0" conf="optional->compile"/>
</dependencies>
</ivy-module>
</ivy-module>

View File

@ -0,0 +1,39 @@
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<context:component-scan base-package="org.springframework.test.context.junit4.orm" />
<tx:annotation-driven />
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:/org/springframework/test/context/junit4/orm/db-schema.sql" />
<jdbc:script location="classpath:/org/springframework/test/context/junit4/orm/db-test-data.sql" />
</jdbc:embedded-database>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
p:dataSource-ref="dataSource">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>org/springframework/test/context/junit4/orm/domain/Person.hbm.xml</value>
<value>org/springframework/test/context/junit4/orm/domain/DriversLicense.hbm.xml</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
</beans>

View File

@ -0,0 +1,109 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4.orm;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction;
import org.hibernate.SessionFactory;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.GenericJDBCException;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.orm.domain.DriversLicense;
import org.springframework.test.context.junit4.orm.domain.Person;
import org.springframework.test.context.junit4.orm.service.PersonService;
/**
* Transactional integration tests regarding <i>automatic vs. manual</i> session
* flushing with Hibernate.
*
* @author Sam Brannen
* @since 3.0
*/
@ContextConfiguration
public class HibernateSessionFlushingTests extends AbstractTransactionalJUnit4SpringContextTests {
private static final String SAM = "Sam";
private static final String JUERGEN = "Juergen";
@Autowired
private PersonService personService;
@Autowired
private SessionFactory sessionFactory;
@Before
public void setUp() {
assertInTransaction(true);
assertNotNull("PersonService should have been autowired.", personService);
assertNotNull("SessionFactory should have been autowired.", sessionFactory);
}
@Test
public void findSam() {
Person sam = personService.findByName(SAM);
assertNotNull("Should be able to find Sam", sam);
DriversLicense driversLicense = sam.getDriversLicense();
assertNotNull("Sam's driver's license should not be null", driversLicense);
assertEquals("Verifying Sam's driver's license number", new Long(1234), driversLicense.getNumber());
}
@Test
public void saveJuergenWithDriversLicense() {
DriversLicense driversLicense = new DriversLicense(2L, 2222L);
Person juergen = new Person(JUERGEN, driversLicense);
personService.save(juergen);
assertNotNull("Should be able to save and retrieve Juergen", personService.findByName(JUERGEN));
assertNotNull("Juergen's ID should have been set", juergen.getId());
}
@Ignore("Disabled until SPR-5699 is resolved")
@Test(expected = ConstraintViolationException.class)
public void saveJuergenWithNullDriversLicense() {
personService.save(new Person(JUERGEN));
}
private void updateSamWithNullDriversLicense() {
Person sam = personService.findByName(SAM);
assertNotNull("Should be able to find Sam", sam);
sam.setDriversLicense(null);
personService.save(sam);
}
@Test(expected = GenericJDBCException.class)
// @IfProfileValue(name = "spring-compatibility", value = "2.5.6")
public void updateSamWithNullDriversLicenseSpring256() {
updateSamWithNullDriversLicense();
sessionFactory.getCurrentSession().flush();
}
@Ignore("Disabled until SPR-5699 is resolved")
@Test(expected = GenericJDBCException.class)
// @Test(expected = UncategorizedSQLException.class)
// @IfProfileValue(name = "spring-compatibility", value = "3.0.0.M2")
public void updateSamWithNullDriversLicenseSpring300() {
updateSamWithNullDriversLicense();
}
}

View File

@ -0,0 +1,16 @@
DROP TABLE drivers_license IF EXISTS;
DROP TABLE person IF EXISTS;
CREATE TABLE person (
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
name VARCHAR(50) NOT NULL,
drivers_license_id INTEGER NOT NULL
);
CREATE UNIQUE INDEX person_name ON person(name);
CREATE UNIQUE INDEX person_drivers_license_id ON person(drivers_license_id);
CREATE TABLE drivers_license (
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
license_number INTEGER NOT NULL
);
CREATE UNIQUE INDEX drivers_license_license_number ON drivers_license(license_number);

View File

@ -0,0 +1,3 @@
INSERT INTO drivers_license(id, license_number) values(1, 1234);
INSERT INTO person(id, name, drivers_license_id) values(1, 'Sam', 1);

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping auto-import="true" default-lazy="false">
<class name="org.springframework.test.context.junit4.orm.domain.DriversLicense" table="drivers_license">
<id name="id" column="id">
<generator class="identity" />
</id>
<property name="number" column="license_number" />
</class>
</hibernate-mapping>

View File

@ -0,0 +1,60 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4.orm.domain;
/**
* DriversLicense POJO.
*
* @author Sam Brannen
* @since 3.0
*/
public class DriversLicense {
private Long id;
private Long number;
public DriversLicense() {
}
public DriversLicense(Long number) {
this(null, number);
}
public DriversLicense(Long id, Long number) {
this.id = id;
this.number = number;
}
public Long getId() {
return this.id;
}
protected void setId(Long id) {
this.id = id;
}
public Long getNumber() {
return this.number;
}
public void setNumber(Long number) {
this.number = number;
}
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping auto-import="true" default-lazy="false">
<class name="org.springframework.test.context.junit4.orm.domain.Person" table="person">
<id name="id" column="id">
<generator class="identity" />
</id>
<property name="name" column="name" />
<many-to-one name="driversLicense" class="org.springframework.test.context.junit4.orm.domain.DriversLicense"
column="drivers_license_id" unique="true" />
</class>
</hibernate-mapping>

View File

@ -0,0 +1,76 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4.orm.domain;
/**
* Person POJO.
*
* @author Sam Brannen
* @since 3.0
*/
public class Person {
private Long id;
private String name;
private DriversLicense driversLicense;
public Person() {
}
public Person(Long id) {
this(id, null, null);
}
public Person(String name) {
this(name, null);
}
public Person(String name, DriversLicense driversLicense) {
this(null, name, driversLicense);
}
public Person(Long id, String name, DriversLicense driversLicense) {
this.id = id;
this.name = name;
this.driversLicense = driversLicense;
}
public Long getId() {
return this.id;
}
protected void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public DriversLicense getDriversLicense() {
return this.driversLicense;
}
public void setDriversLicense(DriversLicense driversLicense) {
this.driversLicense = driversLicense;
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4.orm.repository;
import org.springframework.test.context.junit4.orm.domain.Person;
/**
* Person Repository API.
*
* @author Sam Brannen
* @since 3.0
*/
public interface PersonRepository {
Person findByName(String name);
Person save(Person person);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4.orm.repository.hibernate;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.test.context.junit4.orm.domain.Person;
import org.springframework.test.context.junit4.orm.repository.PersonRepository;
/**
* Hibernate implementation of the {@link PersonRepository} API.
*
* @author Sam Brannen
* @since 3.0
*/
@Repository
public class HibernatePersonRepository implements PersonRepository {
private final SessionFactory sessionFactory;
@Autowired
public HibernatePersonRepository(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Person save(Person person) {
this.sessionFactory.getCurrentSession().save(person);
return person;
}
public Person findByName(String name) {
return (Person) this.sessionFactory.getCurrentSession().createQuery(
"from Person person where person.name = :name").setString("name", name).uniqueResult();
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4.orm.service;
import org.springframework.test.context.junit4.orm.domain.Person;
/**
* Person Service API.
*
* @author Sam Brannen
* @since 3.0
*/
public interface PersonService {
Person findByName(String name);
Person save(Person person);
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4.orm.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.test.context.junit4.orm.domain.Person;
import org.springframework.test.context.junit4.orm.repository.PersonRepository;
import org.springframework.test.context.junit4.orm.service.PersonService;
import org.springframework.transaction.annotation.Transactional;
/**
* Standard implementation of the {@link PersonService} API.
*
* @author Sam Brannen
* @since 3.0
*/
@Service
@Transactional(readOnly = true)
public class StandardPersonService implements PersonService {
private final PersonRepository personRepository;
@Autowired
public StandardPersonService(PersonRepository personRepository) {
this.personRepository = personRepository;
}
public Person findByName(String name) {
return this.personRepository.findByName(name);
}
@Transactional(readOnly = false)
public Person save(Person person) {
return this.personRepository.save(person);
}
}