All,
I'm attempting to write a unit test for a Dao that uses Hibernate. I'm also using Spring, so I'm trying to extend AbstractTransactionalDataSourceSpringContextTests and also use DBUnit to insert data into the database before each test in the onSetUpInTransaction method.
From my logs, I can see that DbUnit is able to successfully insert the data in onSetUpInTransaction just fine. However, when I run a test method that uses the Dao (and therefore, Hibernate) to try to access that data (testGetPersonById2), the data isn't found, even though all this should be happening in the same transaction. After the test method finishes running (it fails), I see the log statement from the AbstractTransactionalDataSourceSpringContextTests that the transaction does get rolled back correctly.
It seems like the onSetUpInTransaction and Hibernate session must be using different transactions, but I can't figure out why. Does anyone have an example of something like this working? Advice on what I'm missing?
Here's what I've got so far:
public class PersonDaoTest extends AbstractTransactionalDataSourceSpringContextTests{
private Log logger = LogFactory.getLog(PersonDaoTest.class);
private PersonDaoImpl personDao;
#Override
public void onSetUpInTransaction() throws Exception {
// Load test data using DBUnit
super.onSetUpBeforeTransaction();
DataSource ds = jdbcTemplate.getDataSource()
Connection con = DataSourceUtils.getConnection(ds);
IDatabaseConnection dbUnitCon = new DatabaseConnection(con);
DatabaseConfig config = dbUnitCon.getConfig();
config.setFeature("http://www.dbunit.org/features/qualifiedTableNames",
true);
//This dataset contains a single entry in the Persons table,
// a new person with Id = 998877665, it gets inserted successfully
IDataSet dataSet = new FlatXmlDataSet(new FileInputStream(
"./PersonDaoTest.xml"));
logger.warn("dataSet = " + dataSet);
try {
DatabaseOperation.REFRESH.execute(dbUnitCon, dataSet);
SessionFactoryUtils.getSession(getSessionFactory(), false).flush();
} finally {
DataSourceUtils.releaseConnection(con, ds);
}
}
//This test PASSES, because the Person with Id = 9 already
//exists in the database, it does not rely on the data being set up in the
// onSetUpInTransaction method
#Test
public void testGetPersonById() {
Person person = personDao.findById(9L);
assertNotNull("person should not be null", person);
}
//This test FAILS at the assertNotNull line, because
//no Person with Id = 998877665 exists in the database,
//even though that Person was inserted
//in the onSetUpInTransaction method - it seems
//that hibernate cannot see that insertion.
#Test
public void testGetPersonById2() {
Person person = personDao.findById(998877665L);
assertNotNull("person should not be null", person);
}
UPDATE: Here's my spring config:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource">
<constructor-arg>
<bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.query_cache_factory">org.hibernate.cache.StandardQueryCacheFactory</prop>
</props>
</property>
</bean>
<!-- The Hibernate interceptor
<bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>-->
<bean id="personDao" class="my.dao.PersonDaoImpl">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
I spent some more time with this, and never was able to find anything that worked when trying to use the onSetUpInTransaction method. I ended up switching over to using onSetUpBeforeTransaction and onTearDownAfterTransaction instead. It's not exactly ideal, because the onSetUpBeforeTransaction method does end up committing its data insertions to the database, and that data must then be cleaned up in onTearDownAfterTransaction. However, the tests themselves can still insert and update data all they want and have those changes all rolled back, since each test does still operate in its own transaction. So, I don't have to do anything special to clean up when a test inserts new data, which means I met one of my goals anyway!
I had a similar problem. here is how I solved it.
I added a code to my abstract testcase class
then I added a datasource with the name "dataSource" which allowed me to use it to insert my test data and create my test sqls using that data source.
The individual datasources datasource1 and datasource2 were correctly injected into my dao beans without any issue.
#Override
protected String[] getConfigLocations()
{
setAutowireMode(AUTOWIRE_BY_NAME);
setDependencyCheck(false);
return new String[] { "classpath:configuration/myappxxx-test-application-context.xml" };
}
Related
I'm trying to open multiple transactions​ on a method using #Transactional by Spring framework
And for some reason it's throws java.lang.IllegalStateException : Transaction already active
My method
#Transactional
Public void foo(Entity e){
entityManager.merge(e);
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
}
Any idea how to open multiple transaction without getting that error?
I think you may be confusing what the Spring #Transactional annotation means. When you use that annotation you're asking Spring to enrich your method invocation with transaction semantics.
You may want to take a look at the TransactionAspectSupport class, more specifically the method invokeWithinTransaction which is the place where all the magic happens for your transactional methods.
You will see there that before your code is invoked, a new transaction is created, then your code is executed, and after that, either a commit or rollback happens. In other words, Spring's aspect controls the transaction for you.
All these magic needs some configuration for it to happen: you need to make sure that Spring finds your #Transactional methods and enrich them. To do so you need to add a piece of configuration:
<tx:annotation-driven/>
And of course you need to define a transaction manager that can be used by your transactional methods. It seems you're using JPA so a JpaTransactionManager makes sense in this case:
<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="database" value="POSTGRESQL"/>
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
<property name="prepareConnection" value="true"/>
</bean>
</property>
<property name="persistenceUnitName" value="test-api"/>
<property name="packagesToScan">
<list>
<value>com.company.humanresources</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<constructor-arg name="emf" ref="entityManagerFactory"/>
</bean>
Finally, if you want to gain access to the entity manager being used by your current transaction, you can do something like:
#PersistenceUnit(unitName = "test-api")
EntityManagerFactory emf;
#Transactional
public Department addDepartment(String name) {
EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(emf);
Department department = new Department();
department.setName(name);
em.persist(department);
return department;
});
Once more, Spring will control the transaction semantics around your transactional method. You must also take into account that the default Spring behavior only works with public methods.
I have such simple class for JUnit test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/mysql-datasource-context.xml"})
public class EmployeeDAOTest {
#Autowired
EmployeeDao employeeDao;
#Test
public void findAllTest() {
assertTrue(employeeDao.findByName("noname").size() == 0);
}
}
The content of the mysql-datasource-context.xml looks like this:
<context:component-scan base-package="my.packages.*"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/project"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="my.packages.entity"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Now the test runs with no problem for my mysql database.
The point is that I also have a postgres database and I need every test run both for the mysql and postgres databases.
The only solution that comes to my mind is creating one more test class with exactly the same tests but annotate it as
#ContextConfiguration(locations = {"classpath:/postgres -datasource-context.xml"})
and create one more datasource context file for it. Unfortunately this way doesn't look like a good solution.
Is there a better way to solve my problem?
I think that the simplest solution is to keep a test class as the base one:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/mysql-datasource-context.xml"})
public class EmployeeDAOTest {
#Autowired
EmployeeDao employeeDao;
#Test
public void findAllTest() {
assertTrue(employeeDao.findByName("noname").size() == 0);
}
}
and then creating one empty subclass for postgres with its own configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/postgres-datasource-context.xml"}, inheritLocations=false)
public class EmployeeDAOTestPostgres extends EmployeeDAOTest {
}
As other suggested you can alter your Spring config files in order to have only one; you can for example put the datasource in a separate context and import it or use a profile (see here for an example)
At a glance is the spring multiple data source configure, actually you can get a lot posts for this via google or quickly search it in stackoverflow
Example:
Spring Boot Multiple Datasource
Another solution I can image is using the spring profile.
I always find it's best to have a top level app context file which includes other files:
appcontext-root.xml
<beans>
<import resource="appcontext-services.xml"/>
<import resource="appcontext-db.xml"/>
</beans>
Then your application can run the context-root.xml, but your tests can test one (or more) of the lower level files.
If you want a swappable back end, you might consider using a PropertyPlaceHolderConfigurer.
eg:
<import resource="appcontext-db-${vendor}.xml"/>
And have a appcontext-db-mysql.xml, appcontext-db-postgres.xml along with System.setProperty("vendor", "mysql")
Im having some trouble understanding the way spring handles the hibernate entities, and does the lazy loading process.
So for this case we have to entities
#Entity
public class EntityA{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ManyToMany(cascade={CascadeType.PERSIST, CascadeType.REFRESH})
private Collection<EntityB> bss= new ArrayList<EntityB>();
and the agregated entity
#Entity
public class EntityB{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ManyToMany(mappedBy="bss")
private Collection<EntityA> ass= new ArrayList<EntityA>();
then I have a simple business class marked as transactional:
#Component
#Scope("session")
#Transactional(propagation=Propagation.TRIED_EVERY_SINGLE_ONE)
public class GenericTestBean {
private EntityA entityA;
#Autowired
private IGenericDAO genericDAO;
public GenericTestBean() {
System.out.println("bean creado!");
}
public void testQuery() {
entityA= genericDAO.get(EntityA.class, 1l);
System.out.println(TransactionIndicatingUtil.getTransactionStatus(true));
System.out.println("is element atached? :" + genericDAO.isAtached(entityA));
//this.loadData();
}
public void loadData(){
System.out.println(TransactionIndicatingUtil.getTransactionStatus(true));
System.out.println("is element atached? :" + genericDAO.isAtached(currentCompany));
System.out.println(entityA.getBss.size());
}
}
and a Simple test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "applicationContext.xml" })
#WebAppConfiguration
public class EntityQueryTest {
// #Autowired
// private SessionFactory sessionFactory;
#Autowired
GenericTestBean genericTestBean;
#Test
public void consultarCompania(){
genericTestBean.testQuery();
genericTestBean.loadData();
}
what Im guessin that should happen is:
1. GenericTestBean gets instantiated
2. testQuery is called from outside the proxy starting the transaction
2. loadData is called, the proxy sees the active transaction, and takes the existent resources
3. the data is retrieived
4. The transacion is closed...
But this doesn't happens, there seems to be two different transactions in each method call, and the entity gets detached between calls, issuing a lazy init exception.
the actual output log is this:
bean creado! --here the object get created
Hibernate: select company0_.companyId as ..... --here the first query get executed
[com.pe.controlLines.data.dao.GenericTestBean.testQuery] --here we check the name for the transaction
is element atached? :true --and see if the element is attached to the session
[com.pe.controlLines.data.dao.GenericTestBean.loadData] --this is in the second method call (with a different transaction name :O )
is element atached? :false --both now, the same element get detached
I tried re-attaching the entity, but this gives me a new query to the database (a new query to table EntityA is sent plus the query to get the objects, which I really don't like).
Im hoping to save one additional query just in order to have lazy loading, or does it have to be this way?, or maybe I have some configuration wrong?
Pdta: I think that the view filter option is even worst than the re-attaching option, it could lead to serious performance issues under high concurrency.
Can anyone please clarify the behavior of transaction contexts between methods calls, and how it get related to the session and the state of the entities?
the TransactionIndicatingUtil implementation is taken from here http://java.dzone.com/articles/monitoring-declarative-transac?page=0,1
and the generic dao is build after this idea
General or specific DAO to record delivery with information from multiple tables?
Update
in case is of some use, here is the spring config file
<context:component-scan base-package="xxxxxx" />
<context:annotation-config />
<context:spring-configured />
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- Data Source Declaration -->
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/xxxx" />
<property name="username" value="xxxxx" />
<property name="password" value="xxxxx" />
<property name="initialSize" value="2" />
<property name="minIdle" value="0" />
<property name="minEvictableIdleTimeMillis" value="120000" />
<property name="maxActive" value="20" />
<property name="maxWait" value="5000" />
</bean>
<!-- Session Factory Declaration <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> -->
<!-- Session Factory Declaration -->
<bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan">
<list>
<value>com.xx.xx.xx.xx</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
<prop key="hibernate.search.default.indexBase">C:/DEVELOPMENT/lucene/indexes</prop>
</props>
</property>
</bean>
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- Transaction Manager is defined -->
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="SessionFactory"/>
</bean>
The Test class should be transactional too
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "applicationContext.xml" })
#Transactional // <--- add
public class EntityQueryTest {
I am assuming that your applicationContext.xml file is the XML code shown in your post
The JUnit test itself is not transactional. Each method of your GenericTestBean bean is transactional. So, each time the non-transactional test calls a method of the transactional bean, a transaction is started, the bean method is executed, and the transaction is committed. Since you call two transactional methods successively, so two separate transactions are started.
If the test method itself was transactional, then a transaction would be started for the test method, and (by default), the two bean methods would execute in the context of the existing transaction, started by the test. The transaction would commit after the test method has returned.
I am working on project where I use Spring Data. I wanted to fill in creationTime field using #CreatedDate annotation instead using method with #PreUpdate or #PrePersist annotation (doing it this way it works perfectly). When I do it with #CreatedDate it just leaves this field blank. I use postgresql database. Documentation is not very helpful.
Do you have any idea how can I fix it? Thank you!
import org.springframework.data.annotation.CreatedDate;
#Entity
#Table(name = "software")
public class Software implements Serializable {
// ...
#Column(name = "creation_time")
#CreatedDate
private Date creationTime;
//...
}
My applicationContext:
<jpa:repositories base-package="path.to.dao"/>
<context:component-scan base-package="path.to.dao"/>
<context:property-placeholder location="classpath:application.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="path.to.bean"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaAdapter"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.ejb.naming_strategy">${hibernate.ejb.naming_strategy}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
I may have been in a similar situation where I wanted the Spring Data JPA #CreatedDate annotation to work, but had no need for the user-level auditing that is otherwise described in their documentation.
To get the annotation-based auditing to work, I had to nonetheless add a class to my project that implemented org.springframework.data.domain.AuditorAware. This is odd because you don't actually seem to use the value returned from the getCurrentAuditor() method that you'll be implementing; mine just returns null.
public class NullAuditorBean implements AuditorAware {
#Override
public Object getCurrentAuditor() {
return null;
}
}
I then needed to reference my "null object" AuditorAware implementation in an entry in my applicationContext to activate the JPA auditing. I had to make sure I did this before the line that specifies the jpa:repositories. This looks something like:
<bean id="auditorBean" class="your.package.subbed.here.NullAuditorBean"/>
<jpa:auditing auditor-aware-ref="auditorBean"/>
I also had to add an orm.xml file, and needed to formally reference it as a property of my entityManagerFactory bean, like so:
<property name="mappingResources">
<value>META-INF/orm.xml</value>
</property>
Make sure this META-INF/orm.xml entry is stored with your compile output (mine is in my WAR under WEB-INF/classes.
That orm.xml file, for the record, contained some boilerplate, which can be found in the answer to this related question.
It was a fair amount of work when I got this working. You may prefer your previous working solution!
This question is quite old, but still relevant. For me the key was this, from the documentation
Since Spring Data MongoDB 1.4 auditing can be enabled by annotating a configuration class with the #EnableMongoAuditing annotation.
For example:
#Configuration
#EnableMongoAuditing
class Config {
/**
* Optional, depending on your needs
*/
#Bean
public AuditorAware<AuditableUser> myAuditorProvider() {
return new AuditorAwareImpl();
}
}
Or, in XML:
<mongo:auditing/>
I have experienced the same issue, but wasn't able to get my head around it.
I have chosen to use Hibernate's #CreationTimestamp instead, and it works like a charm!
I am using dbunit to create database backups, which can be imported and exported. My application can use several database engines: MySQL, PostgreSQL, SQLServer, H2 and Oracle.
All of the above work fine with the following code:
// Connect to the database
conn =BackupManager.getInstance().getConnection();
IDatabaseConnection connection = new DatabaseConnection(conn);
InputSource xmlSource = new InputSource(new FileInputStream(new File(nameXML)));
FlatXmlProducer flatXmlProducer = new FlatXmlProducer(xmlSource);
flatXmlProducer.setColumnSensing(true);
DatabaseOperation.CLEAN_INSERT.execute(connection,new FlatXmlDataSet(flatXmlProducer));
But on Oracle I get this exception:
!ENTRY es.giro.girlabel.backup 1 0 2012-04-11 11:51:40.542
!MESSAGE Start import backup
org.dbunit.database.AmbiguousTableNameException: AQ$_SCHEDULES
at org.dbunit.dataset.OrderedTableNameMap.add(OrderedTableNameMap.java:198)
at org.dbunit.database.DatabaseDataSet.initialize(DatabaseDataSet.java:231)
at org.dbunit.database.DatabaseDataSet.getTableMetaData(DatabaseDataSet.java:281)
at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:109)
at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
at es.giro.girlabel.backup.ImportBackup.createData(ImportBackup.java:39)
at es.giro.girlabel.backup.handlers.Import.execute(Import.java:45)
From the docs:
public class AmbiguousTableNameException extends DataSetException
This exception is thrown by IDataSet when multiple tables having the
same name are accessible. This usually occurs when the database
connection have access to multiple schemas containing identical table
names.
Possible solutions:
1) Use a database connection credential that has
access to only one database schema.
2) Specify a schema name to the
DatabaseConnection or DatabaseDataSourceConnection constructor.
3) Enable the qualified table name support (see How-to documentation).
For whom uses SpringDBUnit. I had struggled with this very annoying issue. I had ended up solving the issue by adding the configuration for com.github.springtestdbunit.bean.DatabaseConfigBean and com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean.
This is my full spring context for SpringDBUnit
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521/XE" />
<property name="username" value="xxxx" />
<property name="password" value="xxxx" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>xxx.example.domain.Person</value>
</list>
</property>
</bean>
<bean id="dbUnitDatabaseConfig" class="com.github.springtestdbunit.bean.DatabaseConfigBean">
<property name="skipOracleRecyclebinTables" value="true" />
<property name="qualifiedTableNames" value="true" />
<!-- <property name="caseSensitiveTableNames" value="true"/> -->
</bean>
<bean id="dbUnitDatabaseConnection"
class="com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="databaseConfig" ref="dbUnitDatabaseConfig" />
<property name="schema" value="<your_schema_name>"/>
</bean>
Setting the database schema fixed it for me:
#Bean
public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection(final DataSource dataSource){
final DatabaseDataSourceConnectionFactoryBean connectionFactory = new DatabaseDataSourceConnectionFactoryBean();
connectionFactory.setDataSource(dataSource);
connectionFactory.setSchema(DB_SCHEMA);
return connectionFactory;
}
I had the same AmbiguousTableNameException while executing Dbunits aginst Oracle DB. It was working fine and started throwing error one day.
Rootcause: while calling a stored procedure, it got modified by mistake to lower case. When changed to upper case it stared working.
I could solve this also by setting the shema name to IDatabaseTester like iDatabaseTester.setSchema("SCHEMANAMEINCAPS")
Also please make sure your connection doesn't access only to many schemas having same table name.
You might encounter issues when importing data from Hibernate before DBUnit runs. According to the database you are using, the casing of table and column names could be important.
For example, in HSQL, database names must be declared in uppercase.
In case you import data via Hibernate's import.sql, make sure the table names are also in uppercase there, otherwise you'll end up with the following problem:
Hibernate creates the tables in lower case
DBUnit reads the table names from the DB in lower case
DBUnit tries to import its datasets using upper case table names
You end up in a mess, with the ambiguous name exception.
Remember to also check whether multiple tables were created during a previous run (both upper and lower case), in which case you need to clean it up too.