I am configuring a simple JPA application using Spring framework.
My goal is to populate the db with data during JUnit Test runs. I understand this is not ideal. But I want it for different purposes.
Here is my persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0">
<persistence-unit name="tothought-tutorial-test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<!-- <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" /> -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
test-context.xml
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.2.xsd">
<!-- Database -->
<!-- <jdbc:embedded-database id="datasource" type="H2"></jdbc:embedded-database> -->
<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/to_thought_tutorial" />
<property name="username" value="demo" />
<property name="password" value="demo" />
</bean>
<!-- Entity Manager -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="persistenceUnitName" value="tothought-tutorial-test" />
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- Jpa Repositories -->
<jpa:repositories base-package="com.cloudfoundry.tothought.repositories"></jpa:repositories>
</beans>
Here is junitTest class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations="classpath:META-INF/test-context.xml")
#Transactional
public class PostPartRepositoryTest {
#Autowired
PostPartRepository repository;
#Test
public void test() {
PostPart postPart = new PostPart();
String body = "Hello";
postPart.setBody(body);
repository.save(postPart);
PostPart dbPostPart = repository.findOne(postPart.getPostPartId());
assertNotNull(dbPostPart);
assertEquals(body, dbPostPart.getBody());
}
#Test
public void insertTest(){
Post post = new Post();
post.setPostDate(new Date());
post.setTitle("First Post");
PostPart postPart = new PostPart();
String body = "Hello";
postPart.setBody(body);
postPart.setPost(post);
repository.save(postPart);
PostPart dbPostPart = repository.findOne(postPart.getPostPartId());
assertNotNull(dbPostPart);
assertNotNull(dbPostPart.getPost());
assertEquals(body, dbPostPart.getBody());
}
}
Both the test passes. But I do not see any entry in tables, although tables are created the first time.
You won't see any entries because you are running the test with #Transactional using the SpringJUnit4ClassRunner. The default for running tests with #Transactional is for any database changes to be automatically rolled back once the test is finished. For more information see this question here
The order in which these things happen is as follows:
Test starts, setup scripts are run, which creates your tables.
Tests start running in transactional context.
Tests finish running, and any database changes made during your test, are automatically rolled back, leaving the database in the state it was in before the tests ran.
You can change this default behaviour you can use #TransactionConfiguration(defaultRollback=false) at the top of the class. However this is bad practice because unit tests should not depend on each other and shouldn't be permanently modifying application state. Also, if you are depending on one test to set something in the environment and use it in the next test, there is no guarantee which order the tests are executed by test runner.
Related
I've used the following configuration in spring and JPA,
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="entityManger"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JPA-01" />
</bean>
<bean id="dao" class="springdao.MessageDAO" />
</beans>
and my persistence.xml is,
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="JPA-01">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/Hibernate" />
<property name="hibernate.connection.username" value="root" />
<property name="hibernate.connection.password" value="password" />
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.max_size" value="20" />
<property name="hibernate.c3p0.timeout" value="300" />
<property name="hibernate.c3p0.max_statements" value="50" />
<property name="hibernate.c3p0.idle_test_period" value="3000" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<!-- <property name="hibernate.hbm2ddl.auto" value="create" />
-->
</properties>
</persistence-unit>
</persistence>
and my junit is,
package test;
import junit.framework.Assert;
import model.Message;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import dao.MessageDAO;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:SpringDAOTest.xml"})
public class SpringDAOTest {
#Autowired
springdao.MessageDAO dao;
#Test
public void testGetMessageById() {
Message message = dao.getMessageById("1");
Assert.assertNotNull(message);
System.out.println(message);
}
#Test
public void testPersistMEssage() {
Message message = new Message();
message.setMessage("Hello World This is the second Message");
dao.persistMessage(message);
}
#Test
public void testUpdateMessage() {
String updatedMessage = "Updated Message for ID 1";
dao.updateMessage(updatedMessage, 1);
}
// TODO updateMessageID
#Test
public void testUpdateMessageID() {
String updatedMessage = "Updated Message for ID 1 with 25";
dao.updateMessageID(updatedMessage, 1);
}
}
I've following questions,
I've autowired the persistence context. I want to assert that the current persistent context is associtated or not?
I've not used the transaction manager configured in the applicationcontext.xml. Just by annotating the classes, I'm able to configure transactions to the services.
I want to get the entity transaction id, so that I want to assert that for the entire service (which involves a lot of daos) uses the same transaction.
1) Provide a getter method for EntityManager in your MessageDAO and use assertNotNull (Although not advisable and not required to test this scenario; you should be testing only your business logic and trust the framework will correctly associate the EntityManager)
2) Reading data from database doesn't require transaction. However, writing data to database does require transaction. Therefore you need to configure a transaction manager for your persistent operation like below
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
You can make a method execute under a transaction in two ways
XML configuration
#Transactional annotation
Annotating your method using #Transactional without a TransactionManager will silently ignore it.
3) I'm not aware of retrieving a transaction id.
However, the primary intention of using a framework like Spring is that someone has already tested infrastructure code for you and you can concentrate on testing only your business logic. Trying to retest may not be a good idea.
As you are using entity manager as the data-access API you can use following transaction manager configuration
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource"/>
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
By default this transaction manager picks up the datasource bean if named "dataSource" and "entityManagerFactory". This transaction manager variety binds the entity manager from the specified entitymanager factory with the current thread. Also it would be worthwhile to have a look at its documentation.
Tests work individually within Eclipse (right click, run as Junit), but when I run them from the command line with maven, it stops while trying to obtain a DataSource connection to the HSQL database.
LogicalConnectionImpl [DEBUG] Obtaining JDBC connection
The oddest part to me is that if I limit the tests being run to 10 (not classes, but individual #Test methods), it will work. But once that 11th test is run it bombs out. The test combinations do not matter, so if I have 30 tests, and I choose 11 or more to run, then it will fail. This made me think it is a DataSource connection max issue, but so far no luck with details of that. I have tried adding heap size just for giggles, but that did not work.
So prior to this hang, I have multiple successful JDBC connection and releases.
Here is my applicationContext-HSQL.xml, which is used for both the in Eclipse and Command Line versions. I know b/c I have forced each of them to fail by messing with the Class values below.
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:flow="http://www.springframework.org/schema/webflow-config"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.company"/>
<import resource="classpath*:/application-context-cxf.xml"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceXmlLocation" value="META-INF/persistence.xml" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:test" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
All of my Test classes utilize Spring 3.2.5, JPA, DBUnit and extend AbstractInMemoryTests.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:applicationContext-hsqldb.xml"})
public class AbstractInMemoryTests {
private static final String FLAT_XML_DATASET = "FlatXmlDataSet.xml";
#Autowired
BasicDataSource bds;
#Before
public void setUp() throws Exception {
DatabaseOperation.CLEAN_INSERT.execute(getConnection(), getDataSet());
}
#SuppressWarnings("deprecation")
private IDataSet getDataSet() throws Exception {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(FLAT_XML_DATASET);
IDataSet dataset = new FlatXmlDataSet(inputStream);
return dataset;
}
private IDatabaseConnection getConnection() throws Exception {
Connection jdbcConnection = bds.getConnection();
IDatabaseConnection connection = new DatabaseConnection(jdbcConnection);
return connection;
}
}
Any ideas on why I may be hanging on that connection, or an idea of how to troubleshoot?
Thanks,
Sean
Per the usual protocol, a good nights sleep helps you think. I completely over-looked the maxActive setting available for the appContext-hsqldb.xml property for my DataSource
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:test" />
<property name="username" value="sa" />
<property name="password" value="" />
****<property name="maxActive" value="-1"/>****
</bean>
Hope this helps someone else in the future.
http://commons.apache.org/dbcp/apidocs/org/apache/commons/dbcp/BasicDataSource.html
if something is hanging you can use "kill -3 {process_number}" on Unix and it gives a thread dump (if not on Unix there is an equivalent on Windows/Mac). That will show where the lock problem is, which may give you an idea what causes it and how to fix it
If the hanging comes after few page access, (maybe 8 which is the default maxTotal), you are not never closing the connection and opening in every request.
Just use entityManager.close(); after the db queries or check if the a connection already exists before creating a new one.
The accepted answer is setting the maxTotal connections to unlimited. Connections will just keep pilling up.
I'm building an application that needs CRUD operations on two separate databases. The transactions are applied to one database or the other (never both...so no need for JTA is my understanding). My setup is pretty close to what is found here: Multiple database with Spring+Hibernate+JPA
The problem: My server (JBoss AS7) starts up fine. The application reads from both datasources, say DS1 and DS2, BUT it can only manipulate data from DS1. I can see sequences (Oracle 11g) being updated but no table updates. There are no errors/exceptions thrown. I suspect one of my transaction managers isn't committing.
Below is a list of technologies used and configuration settings...
Tech Stack
JBoss AS7
Oracle 11g
Spring 3.1
JPA 2
Hibernate 4.1
persistence-ds1.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="pu1">
<class>com.somepackage.EntityA</class>
<class>com.somepackage.EntityB</class>
<class>com.somepackage.EntityC</class>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
</properties>
</persistence-unit>
</persistence>
persistence-ds2.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="pu2">
<class>com.somepackage.EntityD</class>
<class>com.somepackage.EntityE</class>
<class>com.somepackage.EntityF</class>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
</properties>
</persistence-unit>
</persistence>
applicationContext.xml
<?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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup id="ds1" jndi-name="java:jboss/datasources/DS1"
expected-type="javax.sql.DataSource" />
<jee:jndi-lookup id="ds2" jndi-name="java:jboss/datasources/DS2"
expected-type="javax.sql.DataSource" />
<bean id="em1" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="emf1" />
<property name="persistenceUnitName" value="pu1" />
</bean>
<bean id="em2" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="emf2" />
<property name="persistenceUnitName" value="pu2" />
</bean>
<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence-ds1.xml"/>
<property name="dataSource" ref="ds1" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="emf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence-ds2.xml"/>
<property name="dataSource" ref="ds2" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<tx:annotation-driven transaction-manager="txm1" />
<tx:annotation-driven transaction-manager="txm2" />
<bean id="txm1" class="org.springframework.orm.jpa.JpaTransactionManager">
<qualifier value="txMgr1"/>
<property name="entityManagerFactory" ref="emf1" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="txm2" class="org.springframework.orm.jpa.JpaTransactionManager">
<qualifier value="txMgr2"/>
<property name="entityManagerFactory" ref="emf2" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
</beans>
In my DAOs, I reference the transaction managers at the class-level as follows.
#Transactional("txm1")
public class DAO1 { ... }
#Transactional("txm2")
public class DAO2 { ... }
I resolved my issue!
In my applicationContext.xml, I removed the following.
<tx:annotation-driven transaction-manager="txm1" />
<tx:annotation-driven transaction-manager="txm2" />
And used the following instead.
<tx:annotation-driven />
But here's what I believe was the kicker (main problem). In my DAOs, I was assigning the two transaction managers at the class-level. But then I was overriding them with the way I was declaring my methods.
#Transactional(readOnly = false, value = "txm1")
public abstract class AbstractJpaDAO1<T extends Serializable> {
...
#Transactional(readOnly = true)
public T findById(final Long id) {...}
#Transactional
public boolean insert(final T entity) {...}
As you can see, the #Transaction annotations on the methods were overriding the the one at the class-level. And because there was no transaction manager specified on the methods, Spring defaulted to "transactionManager", which I didn't (and still don't) have declared in my applicaitonContext.xml. So, it was trying to commit using a transaction manager that didn't exist.
For the resolution, I just removed the #Transitional annotations on the methods, and kept the one at the class-level.
#Transactional(readOnly = false, value = "txm1")
public abstract class AbstractJpaDAO1<T extends Serializable> {
...
public T findById(final Long id) {...}
public boolean insert(final T entity) {...}
Now everything works! I can read/write to two separate databases.
I'm setting up a maven-spring-hibernate-mysql-tomcat environment.
I would like to inject my Entity manager using the #PersistenceContext annotation.
As I understand to do this, I should have PersistenceAnnotationBeanPostProcessor defined in my application context, pointing to my persistence.xml file.
In this case my application context could be looking like this more or less:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task" xmlns:ox="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-3.1.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- Context -->
<context:component-scan base-package="com.yl.mypack" />
<!-- AOP -->
<aop:aspectj-autoproxy />
<!-- Properties -->
<context:property-placeholder
location="classpath:db.connection.properties,applicationProperties.properties" />
<!-- DB Connection Pool -->
<bean id="dataSourceGlobal" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- Data Source -->
<property name="driverClass" value="${driverClass}" />
<property name="jdbcUrl" value="${jdbcUrl}" />
<property name="user" value="${user}" />
<property name="password" value="${password}" />
<!-- C3P0 Connection pool properties -->
<property name="minPoolSize" value="${c3p0.min_pool_size}" />
<property name="maxPoolSize" value="${c3p0.max_pool_size}" />
<property name="unreturnedConnectionTimeout" value="${c3p0.timeout}" />
<property name="idleConnectionTestPeriod" value="${c3p0.idle_test_period}" />
<property name="maxStatements" value="${c3p0.max_statements}" />
<property name="automaticTestTable" value="${c3p0.automatic_test_table}" />
</bean>
<!-- JPA -->
<!-- Creates a EntityManagerFactory for use with the Hibernate JPA provider -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
<property name="persistenceUnitName" value="myPU" />
<property name="dataSource" ref="dataSourceGlobal" />
</bean>
<!-- In order to enable EntityManager injection -->
<bean id="persistenceAnnotation"
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
<property name="persistenceUnits">
<map>
<entry key="myPU" value="classpath:META-INF/persistence.xml" />
</map>
</property>
</bean>
<!-- Transactions -->
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSourceGlobal" />
</bean>
</beans>
My persistence.xml could look like this:
<persistence-unit name="myPU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.transaction.flush_before_completion"
value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
So now I guess I should be able to inject my entity manager using the #PersistenceContext annotation, at list this is what I get from the documentation. Before I'mm getting to JpaVendorAdapter, my first question would refer the entity manager factory definition:
The following properties:
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
<property name="persistenceUnitName" value="myPU" />
Are these required to be referred from the entity manager factory? Is it a must?
My second question would be regarding the JpaVendorAdapter, and in my case HibernateJpaVendorAdapter.
If I use HibernateJpaVendorAdapter, do I still need to have a persistence.xml file? Since some of the properties are overlapping. Moreover, do I still need to have PersistenceAnnotationBeanPostProcessor defined, pointing to my persistence.xml file? Can these 2 go together (PersistenceAnnotationBeanPostProcessor and HibernateJpaVendorAdapter)? Should they go together? What is the best practice, assuming I'm avoiding any JDNI style definitions?
Thanks in advance
The combination of data source bean and HibernateJpaVendorAdapter allows you to get rid of persistence.xml with Spring 3.1. Check out this article:
http://www.baeldung.com/2011/12/13/the-persistence-layer-with-spring-3-1-and-jpa/
So the answers:
They are not a must.
No, you don't need to have a persistence.xml.
I am not exactly sure of what use PersistenceAnnotationBeanPostProcessor is.
<context:component-scan base-package="com.demo.dao" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="hibernate-resourceLocal"/>
</bean>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
My Spring application context xml looks as simple as this. And it is working.
I don't what the best practice is, but I will keep persistence.xml so that in case I need to expose my service as session bean, it can be easily done.
I have a java project using Spring 3.0 , JPA 2.0 with MyEclipse IDE
Trying to convert some basic dao integration tests to spring and have run into a few issues. Here's my setup:
LevelDAO
public class LevelDAO extends JpaDaoSupport implements ILevelDAO
{
public void save(Level entity) {
logger.info("saving Level instance");
try {
getJpaTemplate().persist(entity);
logger.info("save successful");
} catch (RuntimeException re) {
logger.error("save failed", re);
throw re;
}
}
}
Unit Test
#Transactional
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:applicationContext.xml"})
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
public class LevelDaoImplTests {
LevelDAO levelDao;
#Test
public void shouldSaveNewLevels() {
levelDao= new LevelDAO();
Level l = new Level();
l.setName = "test";
levelDao.save(l);
}
}
Persistence.Xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="t1" transaction-type="RESOURCE_LOCAL">
<provider>
org.eclipse.persistence.jpa.PersistenceProvider
</provider>
<class>com.nlg.model.Level</class>
<properties>
<property name="javax.persistence.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://myserver.rds.amazonaws.com:3306/" />
<property name="javax.persistence.jdbc.user" value="myuser" />
<property name="javax.persistence.jdbc.password" value="mypass" />
</properties>
</persistence-unit>
applicationContext.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="t1" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean
id="LevelDAO" class="com.nlg.model.LevelDAO">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
At first I recieved this
Value '2.0' of attribute 'version' of element 'persistence' is not valid
So reading another post which suggested changing this to "1.0"
and now recieve
java.lang.IllegalStateException: Failed to load ApplicationContext
That issue was resolved with the < provider > tag however hasn't fixed my issue:
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is Exception [EclipseLink-4021] (Eclipse Persistence Services - 1.0.2 (Build 20081024)): org.eclipse.persistence.exceptions.DatabaseException
Exception Description: Unable to acquire a connection from driver [null], user [null] and URL [null].
My concern is that by downgrading the version no. to "1.0" that I'm also overlooking the issue of compatibility within this stack. I have non-spring versions of these tests working, so any ideas on where I've gone wrong appreciated.
Thanks
Unable to acquire a connection from driver [null], user [null] and URL [null]
These are JPA 2.0 properties:
<property name="javax.persistence.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://myserver.rds.amazonaws.com:3306/" />
<property name="javax.persistence.jdbc.user" value="myuser" />
<property name="javax.persistence.jdbc.password" value="mypass" />
So if you switched back to 1.0, you'd probably want:
<property name="eclipelink.jdbc.url" value="jdbc:mysql://myserver.rds.amazonaws.com:3306/"/>
<property name="eclipelink.jdbc.user" value="myuser"/>
<property name="eclipelink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="eclipelink.jdbc.password" value="mypass"/>
But then I would recommend to solve "that other problem" and stay with 2.0
Here is an example of JPA 2.0 over EclipseLink that works ( notice persistence version="2.0" ):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="eclipselinktest" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- list all classes -->
<class>com.codesmuggler.model.User</class>
<properties>
<!-- some properties needed by persistence provider:
- driver
- db url
- db user name
- db user password -->
<property name="javax.persistence.target-database" value="PostgreSQL"/>
<property name="javax.persistence.logging.level" value="INFO"/>
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/testdb"/>
<property name="javax.persistence.jdbc.user" value="testuser"/>
<property name="javax.persistence.jdbc.password" value="testpassword"/>
<!-- for testing purpose every time application is launched drop and create tables
in production mode - this line should be removed or commented out
-->
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
</properties>
</persistence-unit>
</persistence>
Take a look at the example in full