I'm trying to persist an entity using. My test case works (data are persisted in db) when I handle my transaction myself.
public User saveUser(User user) {
getEm().getTransaction().begin();
getEm().persist(user);
getEm().getTransaction().commit();
return user;
}
(entity manager comes from a template class which my DAO class extends)
It stops persisiting data when I configure spring to handle transactions.
test-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="domainPU" />
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://192.168.5.111/testdb" />
<property name="username" value="sdgdsgs" />
<property name="password" value="sdfgdsg" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory">
<ref local="entityManagerFactory" />
</property>
</bean>
</beans>
UsersRepositoryTest:
#ContextConfiguration(locations = { "classpath:test-context.xml", "classpath:module-context.xml" })
#TransactionConfiguration(defaultRollback=false)
public class UsersRepositoryTest extends AbstractTransactionalTestNGSpringContextTests {
#Autowired
private UsersRepository usersRepository;
#Test(dependsOnMethods = {"findUserByLogin"})
public void registerUser() throws DataAccessException {
User myUser = getUserHomer();
usersRepository.saveUser(myUser);
User returnedUser = usersRepository.getUserByLogin(myUser.getLogin());
assertNotNull(returnedUser);
...
}
}
stacktrace:
2012-10-22 08:26:26 org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean createNativeEntityManagerFactory
INFO: Building JPA container EntityManagerFactory for persistence unit 'domainPU'
2012-10-22 08:26:26 org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
2012-10-22 08:26:26 org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.1.6.Final}
2012-10-22 08:26:26 org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
2012-10-22 08:26:26 org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
2012-10-22 08:26:26 org.hibernate.ejb.Ejb3Configuration configure
INFO: HHH000204: Processing PersistenceUnitInfo [
name: domainPU
...]
2012-10-22 08:26:26 org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator instantiateExplicitConnectionProvider
INFO: HHH000130: Instantiating explicit connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
2012-10-22 08:26:27 org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
2012-10-22 08:26:27 org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
2012-10-22 08:26:27 org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory
2012-10-22 08:26:27 org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
2012-10-22 08:26:27 org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'entityManagerFactory' of type [class org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2012-10-22 08:26:27 org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'hibernateTranslator' of type [class org.springframework.orm.hibernate4.HibernateExceptionTranslator] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2012-10-22 08:26:27 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#5c28305d: defining beans [org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,entityManagerFactory,dataSource,transactionManager,org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0,hibernateTranslator,usersDao,zoneDao,usersRepository,zoneRepository,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
2012-10-22 08:26:27 org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager#3341b736]; rollback [false]
Hibernate: select user0_.id as id0_, user0_.active as active0_, user0_.creation_date as creation3_0_, user0_.email as email0_, user0_.last_login_date as last5_0_, user0_.login as login0_, user0_.password as password0_, user0_1_.AVATAR as AVATAR1_, user0_1_.FIRST_NAME as FIRST2_1_, user0_1_.ID as ID1_, user0_1_.LAST_NAME as LAST4_1_, case when user0_1_.id is not null then 1 when user0_.id is not null then 0 end as clazz_ from user user0_ left outer join client user0_1_ on user0_.id=user0_1_.id where user0_.login=?
Hibernate: select phone0_.id as id2_0_, phone0_.phone_number as phone2_2_0_, phone0_.user_id as user3_2_0_ from phone phone0_ where phone0_.id=?
Hibernate: select address0_.ID as ID6_0_, address0_.apartment_number as apartment2_6_0_, address0_.city as city6_0_, address0_.country as country6_0_, address0_.house_number as house5_6_0_, address0_.post_code as post6_6_0_, address0_.street as street6_0_ from address address0_ where address0_.ID=?
Hibernate: select user0_.id as id0_, user0_.active as active0_, user0_.creation_date as creation3_0_, user0_.email as email0_, user0_.last_login_date as last5_0_, user0_.login as login0_, user0_.password as password0_, user0_1_.AVATAR as AVATAR1_, user0_1_.FIRST_NAME as FIRST2_1_, user0_1_.ID as ID1_, user0_1_.LAST_NAME as LAST4_1_, case when user0_1_.id is not null then 1 when user0_.id is not null then 0 end as clazz_ from user user0_ left outer join client user0_1_ on user0_.id=user0_1_.id where user0_.login=?
2012-10-22 08:26:27 org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Committed transaction after test execution for test context [[TestContext#63edf84f testClass = UsersRepositoryTest, testInstance = pl.eports.zonen.user.repository.UsersRepositoryTest#7e3bc473, testMethod = findUserByLogin#UsersRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#1c493dca testClass = UsersRepositoryTest, locations = '{classpath:test-context.xml, classpath:module-context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
2012-10-22 08:26:27 org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (2): transaction manager [org.springframework.orm.jpa.JpaTransactionManager#3341b736]; rollback [false]
Hibernate: select user0_.id as id0_, user0_.active as active0_, user0_.creation_date as creation3_0_, user0_.email as email0_, user0_.last_login_date as last5_0_, user0_.login as login0_, user0_.password as password0_, user0_1_.AVATAR as AVATAR1_, user0_1_.FIRST_NAME as FIRST2_1_, user0_1_.ID as ID1_, user0_1_.LAST_NAME as LAST4_1_, case when user0_1_.id is not null then 1 when user0_.id is not null then 0 end as clazz_ from user user0_ left outer join client user0_1_ on user0_.id=user0_1_.id where user0_.login=?
2012-10-22 08:26:27 org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Committed transaction after test execution for test context [[TestContext#63edf84f testClass = UsersRepositoryTest, testInstance = pl.eports.zonen.user.repository.UsersRepositoryTest#7e3bc473, testMethod = registerUser#UsersRepositoryTest, testException = java.lang.AssertionError: expected object to not be null, mergedContextConfiguration = [MergedContextConfiguration#1c493dca testClass = UsersRepositoryTest, locations = '{classpath:test-context.xml, classpath:module-context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
PASSED: findUserByLogin
FAILED: registerUser
java.lang.AssertionError: expected object to not be null
at org.testng.Assert.fail(Assert.java:94)
...
As you can see from the stacktrace, transaction seems to be started and finished, but no sql inserts are produced and no data are inserted into db (data rollback is set to false)
I've tried force flushing data after persist() but spring managed transaction seems to be finished by then.
I've looked for a similar issue on forums but none works.
I can provide some more code if necessary.
I'm using Spring 3.1.2 and Hibernate 4.1.6.Final
update:
DAO: (#Transactional annotation is put here instead on service layer temporarily)
#Repository
public class JpaUsersDAO extends JpaDAOTemplate<User> implements UsersDAO {
public JpaUsersDAO(EntityManagerFactory factory) {
super(factory.createEntityManager(), User.class);
}
#Transactional
public User saveUser(User user) {
getEm().persist(user);
return user;
}
}
DAOTemplate:
public abstract class JpaDAOTemplate<T extends Serializable> {
private EntityManager em;
private Class<T> clazz;
public JpaDAOTemplate(EntityManager em, final Class<T> clazz) {
this.em = em;
this.clazz = clazz;
}
public EntityManager getEm() {
return em;
}
public T getById(Integer id) {...}
...
}
bean definition:
<bean id="usersDao"
class="pl.package.user.dao.impl.JpaUsersDAO">
<constructor-arg ref="entityManagerFactory" />
</bean>
It seems that the transaction is lost somewhere after selects and before calling getEm().persist() - org.hibernate.ejb.TransactionImpl#tx is null when calling persist() but it was org.hibernate.engine.transaction.internal.jdbc.JDBCTransaction before the call (when sql select statements calls were made)
update 2
debug level stacktrace:
[2012-10-23 11:15:14,546]DEBUG 38629[main] - org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:365) - Creating new transaction with name [registerUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[2012-10-23 11:15:33,252]DEBUG 57335[main] - org.hibernate.internal.SessionImpl.<init>(SessionImpl.java:316) - Opened session at timestamp: 13509837332
[2012-10-23 11:15:33,252]DEBUG 57335[main] - org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:368) - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl#18025c5c] for JPA transaction
[2012-10-23 11:15:40,085]DEBUG 64168[main] - org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:158) - begin
[2012-10-23 11:15:40,101]DEBUG 64184[main] - org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:295) - Obtaining JDBC connection
[2012-10-23 11:15:40,101]DEBUG 64184[main] - org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:301) - Obtained JDBC connection
[2012-10-23 11:15:40,101]DEBUG 64184[main] - org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:69) - initial autocommit status: true
[2012-10-23 11:15:40,101]DEBUG 64184[main] - org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:71) - disabling autocommit
[2012-10-23 11:16:06,934]DEBUG 91017[main] - org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:407) - Not exposing JPA transaction [org.hibernate.ejb.EntityManagerImpl#18025c5c] as JDBC transaction because JpaDialect [org.springframework.orm.jpa.DefaultJpaDialect#5f343722] does not support JDBC Connection retrieval
[2012-10-23 11:16:06,934]DEBUG 91017[main] - org.springframework.test.context.transaction.TransactionalTestExecutionListener.isRollback(TransactionalTestExecutionListener.java:357) - No method-level #Rollback override: using default rollback [false] for test context [[TestContext#5809fdee testClass = UsersRepositoryTest, testInstance = pl.eports.zonen.user.repository.UsersRepositoryTest#3fde891b, testMethod = registerUser#UsersRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#77fe4169 testClass = UsersRepositoryTest, locations = '{classpath:test-context.xml, classpath:module-context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
[2012-10-23 11:16:06,934] INFO 91017[main] - org.springframework.test.context.transaction.TransactionalTestExecutionListener.startNewTransaction(TransactionalTestExecutionListener.java:275) - Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager#37977909]; rollback [false]
[2012-10-23 11:17:08,103]DEBUG152186[main] - org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245) - Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
[2012-10-23 11:17:08,118]DEBUG152201[main] - org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:106) - Adding transactional method 'saveUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[2012-10-23 11:17:08,118]DEBUG152201[main] - org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245) - Returning cached instance of singleton bean 'txManager'
[2012-10-23 11:17:27,073]DEBUG171156[main] - org.springframework.orm.jpa.JpaTransactionManager.doGetTransaction(JpaTransactionManager.java:331) - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl#18025c5c] for JPA transaction
[2012-10-23 11:18:04,031]DEBUG208114[main] - org.springframework.transaction.support.AbstractPlatformTransactionManager.handleExistingTransaction(AbstractPlatformTransactionManager.java:470) - Participating in existing transaction
Final update:
Problem was in the way I injected EntityManagerFactory to my DAO. I used applicationContext.xml configuration file to inject it (this way EMF does not participate in transaction). To have it working I changed my DAO class to:
#Repository
public class JpaUsersDAO extends JpaDAOTemplate<User> implements UsersDAO {
#PersistenceContext
private EntityManager em;
...
}
You are using Spring 3.0.
I am not clear your coding public User saveUser(User user) method. Even If you use Spring 3.0, you handel the transaction your self(Bean Management Transaction).
It just need to use #Transactional(propagation = Propagation.REQUIRED) annotation. Change propagation type based on your process.
Example DAO :
GroupDAO.java
#Repository("GroupDAO")
public class GroupDAO {
#PersistenceContext
protected EntityManager em;
#Transactional(propagation = Propagation.REQUIRED)
public void insert(Group group) {
try {
em.persist(group);
em.flush();
} catch (PersistenceException pe) {
}
}
}
spring-bean.xml with EclipseLink JPA <-- just for reference.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:faces="http://www.springframework.org/schema/faces"
xmlns:int-security="http://www.springframework.org/schema/integration/security"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:sec="http://www.springframework.org/schema/security"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/integration/security http://www.springframework.org/schema/integration/security/spring-integration-security-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/faces http://www.springframework.org/schema/faces/spring-faces-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.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="your-package"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.5.111/testdb"/>
<property name="username" value="your-username"/>
<property name="password" value="your-password"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- <property name="dataSource" ref="dataSource"/>-->
<property name="persistenceUnitName" value="domainPU"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
</property>
<property name="jpaPropertyMap">
<props>
<prop key="eclipselink.weaving">false</prop>
</props>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver">
</bean>
</property>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform"/>
<!-- <property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform" />-->
<property name="generateDdl" value="false"/>
<property name="showSql" value="true"/>
</bean>
</beans>
Related
Couldn't find what is wrong with inserting data in mySQL database using Spring data, JPA, hibernate and mySQL. It is inserting data twice in database.
The root-context.xml file is:
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
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-4.0.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.8.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<context:component-scan base-package="com.project.db">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<jdbc:embedded-database type="HSQL" id="dataSource"/>
<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/jpa"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean> -->
<!-- <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
</bean> -->
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property name="packagesToScan" value="com.project.db.entity"></property>
<property name="dataSource" ref="dataSource"></property>
<!-- <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> -->
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<jpa:repositories base-package="com.project.db.repository"/>
</beans>
The servlet-context.xml file is:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
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">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.project.db" />
</beans:beans>
My #Entity class is:
#Entity
public class User {
#Id
#GeneratedValue
private Integer id ;
private String name ;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
JPA repository is:
import org.springframework.data.jpa.repository.JpaRepository;
import com.project.entity.User;
public interface UserRepository extends JpaRepository<User, Integer> {
}
And, finally, #Service class is:
import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.project.entity.User;
import com.project.repository.UserRepository;
#Transactional
#Service
public class InitDbService {
#Autowired
private UserRepository userRepository;
#PostConstruct
public void init() {
User user = new User();
user.setName("Ali");
userRepository.save(user);
}
}
The above code works without errors/exceptions; database/table is also created but data is inserted into Entity/table twice when I see that in mySQL database.
Project is at github.
Console output is:
INFO: Spring WebApplicationInitializers detected on classpath: [com.project.db.WebAppInitializer#1867584]
Sep 2, 2015 12:50:17 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
INFO : org.springframework.web.context.support.XmlWebApplicationContext - Refreshing Root WebApplicationContext: startup date [Wed Sep 02 12:50:17 PKT 2015]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/root-context.xml]
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Hibernate: drop table if exists users
Hibernate: create table users (id integer not null auto_increment, name varchar(255), primary key (id))
Hibernate: insert into users (name) values (?) // first time inserting here and
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 5633 ms
Sep 2, 2015 12:50:23 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'springDispatcher'
INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'springDispatcher': initialization started
INFO : org.springframework.web.context.support.XmlWebApplicationContext - Refreshing WebApplicationContext for namespace 'springDispatcher-servlet': startup date [Wed Sep 02 12:50:23 PKT 2015]; parent: Root WebApplicationContext
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/appServlet/servlet-context.xml]
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.project.db.HomeController.home(java.util.Locale,org.springframework.ui.Model)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for #ControllerAdvice: WebApplicationContext for namespace 'springDispatcher-servlet': startup date [Wed Sep 02 12:50:23 PKT 2015]; parent: Root WebApplicationContext
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for #ControllerAdvice: WebApplicationContext for namespace 'springDispatcher-servlet': startup date [Wed Sep 02 12:50:23 PKT 2015]; parent: Root WebApplicationContext
INFO : org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped URL path [/resources/**] onto handler 'org.springframework.web.servlet.resource.ResourceHttpRequestHandler#0'
Hibernate: insert into users (name) values (?) // Second time inserting here
INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'springDispatcher': initialization completed in 1483 ms
Sep 2, 2015 12:50:25 PM org.apache.catalina.core.StandardContext reload
INFO: Reloading Context with name [/db] is completed
Taking a chance here since I see that you are using Spring MVC.
With Spring MVC, you have a servlet-context which defines the controllers, and an applicationContext for other beans. It might be that you are scanning for beans other than controllers in the servlet-context, which in turn will give you two beans of InitDbService, both running their #PostConstruct-method, inserting into the database.
This can be solved by defining component-scan like this:
servlet-context (after placing controllers and controllers only in a separate package):
<context:component-scan base-package="com.my.project.controller" />
applicationContext:
<context:component-scan base-package="com.my.project">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
You have to enable DEBUG logging to check that your initailizing bean isn't created twice, as Tobb mentioned before your bean is probabbly created in both contexts. Log stands clearly that first insert is executed during root context initialization (witch is correct) and second time during servlet context initialization (which is wrong)
I have found solution to your problem: You have to add commponent scan without default filters to your root-context
<context:component-scan base-package="com.project.db" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
and servlet-context is
<context:component-scan base-package="com.project.db" />
I have tested your project and its working fine with this change.
Programmers! I don't understand how doeas the propagation attribute work in the #Transactional annotation. Please, help)
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="packagesToScan" value="com.springapp.mvc"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="jdbc.fetch_size">50</prop>
<prop key="hbm2ddl.auto">create-drop</prop>
</props>
</property>
<property name = "dataSource" ref = "dataSource"></property>
</bean>
Service class:
#Service
public class BookManager implements IBookManager {
#Autowired
private SessionFactory sessionFactory;
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1() {
Session session = sessionFactory.getCurrentSession();
Book book = (Book) session.load(Book.class, 1);
System.out.println("first: " + book.getTitle());
method2();
}
#Override
#Transactional(propagation = Propagation.NEVER)
public void method2() {
System.out.println("hello");
}
}
I expect that the method method2() throws an exception, as it is annotated with Propagation.NEVER. But this is not happening.
Output
июн 27, 2015 3:35:35 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
июн 27, 2015 3:35:35 PM org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
июн 27, 2015 3:35:36 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
июн 27, 2015 3:35:36 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
июн 27, 2015 3:35:36 PM org.springframework.orm.hibernate4.HibernateTransactionManager afterPropertiesSet
INFO: Using DataSource [org.apache.commons.dbcp.BasicDataSource#6c5945a7] of Hibernate SessionFactory for HibernateTransactionManager
Hibernate: select book0_.id as id1_0_0_, book0_.title as title2_0_0_ from books book0_ where book0_.id=?
first: 33
hello
Process finished with exit code 0
Why it doesn't work?
Thanks :)
Transactions in Spring are proxy-based: when a bean A calls a transactional bean B, it actually calls a method of a dynamic proxy, which deals with the opening of the transaction, then delegates to the actual bean B, then deals with the commit/rollback of the transaction.
If you call a method2 from a method1 of a single bean A, your call is not intercepted by the transactional proxy anymore, and Spring is thus completely unaware that method2() has been called. So nothing can check that there is no transaction.
Put the method2 in another bean, injected in BookManager, and everything will work as expected.
I have an application using Spring 3.2.2 and Hibernate 3.6.0.Final. I made some configurations and the app works pretty well on the test environment, using Postgresql, etc.
Junit Stach trace:
enter code here
java.lang.AssertionError: Error creating bean with name 'entityManagerFactory' defined in class path resource [applicationContext.xml]:
Invocation of init method failed; nested exception is javax.persistence.PersistenceException:
[PersistenceUnit: P_PROJET] Unable to build EntityManagerFactory
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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/projet" />
<property name="username" value="postgres" />
<property name="password" value="" />
</bean>
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="defaultDataSource" ref="datasource"></property>
<property name="persistenceXmlLocation" value="classpath:META-INF/persistance.xml">
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager"></property>
<property name="persistenceUnitName" value="P_PROJET"></property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:annotation-config></context:annotation-config>
</beans>
Persistance.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="P_PROJET" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
</properties>
</persistence-unit>
</persistence>
console stack trace:
INFO : org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#4476128: startup date [Mon Apr 07 21:55:10 WET 2014]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : org.springframework.jdbc.datasource.DriverManagerDataSource - Loaded JDBC driver: org.postgresql.Driver
INFO : org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Building JPA container EntityManagerFactory for persistence unit 'P_PROJET'
INFO : org.hibernate.annotations.common.Version - Hibernate Commons Annotations 3.2.0.Final
INFO : org.hibernate.cfg.Environment - Hibernate 3.6.0.Final
INFO : org.hibernate.cfg.Environment - hibernate.properties not found
INFO : org.hibernate.cfg.Environment - Bytecode provider name : javassist
INFO : org.hibernate.cfg.Environment - using JDK 1.4 java.sql.Timestamp handling
INFO : org.hibernate.ejb.Version - Hibernate EntityManager 3.6.0.Final
INFO : org.hibernate.ejb.Ejb3Configuration - Processing PersistenceUnitInfo [
name: P_PROJET
...]
INFO : org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.gestion.projet.entities.EquipeProjet
INFO : org.hibernate.cfg.annotations.EntityBinder - Bind entity com.gestion.projet.entities.EquipeProjet on table EquipeProjet
INFO : org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.gestion.projet.entities.MembreTache
INFO : org.hibernate.cfg.annotations.EntityBinder - Bind entity com.gestion.projet.entities.MembreTache on table MembreTache
INFO : org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.gestion.projet.entities.User
INFO : org.hibernate.cfg.annotations.EntityBinder - Bind entity com.gestion.projet.entities.User on table User
INFO : org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.gestion.projet.entities.Projet
INFO : org.hibernate.cfg.annotations.EntityBinder - Bind entity com.gestion.projet.entities.Projet on table Projet
INFO : org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.gestion.projet.entities.Phase
INFO : org.hibernate.cfg.annotations.EntityBinder - Bind entity com.gestion.projet.entities.Phase on table Phase
INFO : org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.gestion.projet.entities.Role
INFO : org.hibernate.cfg.annotations.EntityBinder - Bind entity com.gestion.projet.entities.Role on table Role
INFO : org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.gestion.projet.entities.Tache
INFO : org.hibernate.cfg.annotations.EntityBinder - Bind entity com.gestion.projet.entities.Tache on table Tache
INFO : org.hibernate.cfg.annotations.CollectionBinder - Mapping collection: com.gestion.projet.entities.EquipeProjet.user -> User
INFO : org.hibernate.cfg.annotations.CollectionBinder - Mapping collection: com.gestion.projet.entities.User.membretache -> MembreTache
INFO : org.hibernate.cfg.annotations.CollectionBinder - Mapping collection: com.gestion.projet.entities.Projet.phases -> Phase
INFO : org.hibernate.cfg.annotations.CollectionBinder - Mapping collection: com.gestion.projet.entities.Phase.tache -> Tache
INFO : org.hibernate.cfg.annotations.CollectionBinder - Mapping collection: com.gestion.projet.entities.Tache.membreTaches -> MembreTache
INFO : org.hibernate.cfg.Configuration - Hibernate Validator not found: ignoring
INFO : org.hibernate.cfg.search.HibernateSearchEventListenerRegister - Unable to find org.hibernate.search.event.FullTextIndexEventListener on the classpath. Hibernate Search is not enabled.
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#8c3c315: defining beans [datasource,persistenceUnitManager,entityManagerFactory,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
Looks like you're missing the hibernate-search jar.
See http://hibernate.org/search/
I have the following service classes:
public class UserLoginServiceImpl implements UserLoginService {
private UserDAO dao;
public UserLoginServiceImpl(UserDAO dao) {this.dao = dao; }
public User login(String userName, String password) {
User u = dao.findUserByCredentials(userName, password);
if (u == null) {
throw new UserNotFoundException();
}
return u;
}
public class UserManagementServiceImpl implements UserManagementService {
private UserDAO dao;
public UserManagementServiceImpl(UserDAO dao) { this.dao = dao; }
public void createUser(User u) {
dao.save(u);
}
}
My service interfaces reside under com.mysystem.services package and my service implementations under com.mysystem.services.impl package.
I am using hibernate as my jpa implementation and declarative transactions in spring. My configuration file is the following:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethod" expression="execution(* com.mysystem.services.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>
<!--
Beans
-->
<bean id="userDao" class="com.mysystem.dao.UserDAOImpl">
<constructor-arg ref="entityManagerFactory" />
</bean>
<bean id="userLoginService" class="com.mysystem.services.impl.UserLoginServiceImpl">
<constructor-arg ref="userDao" />
</bean>
<bean id="userManagementService" class="com.mysystem.services.impl.UserManagementServiceImpl">
<constructor-arg ref="userDao" />
</bean>
Lastly, somewhere in my code i run the following:
UserManagementService userManagementService = context.getBean(UserManagementService.class);
userManagementService.createUser(new User("test", "test"));
UserLoginService userLogginService = context.getBean(UserLoginService.class);
User user = userLogginService.login("test", "test");
which results in the login() method throwing an UserNotFoundException because it cannot find the user inserted by createUser() previously which means that hibernate will not flush the session between method calls. I can verify this form the console output (i can see hibernate's create and select statements but not insert).
Why isn't the transaction committed soon after the call to createUser()? What am i doing wrong here?
EDIT:
Using the #Transactional annotation instead of declarative transactions works. Using #Transactional however is not an option for me. I need to implement declarative transactions.
Below is the spring's debug output:
13:03:18,174 DEBUG [main] jpa.JpaTransactionManager - Creating new transaction with name [com.mysystem.services.impl.UserManagementServiceImpl.createUser]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
13:03:18,175 DEBUG [main] jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl#1af6a711] for JPA transaction
Hibernate:
select
nextval ('hibernate_sequence')
13:03:18,255 DEBUG [main] jpa.JpaTransactionManager - Initiating transaction commit
13:03:18,255 DEBUG [main] jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl#1af6a711]
13:03:18,256 DEBUG [main] jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl#1af6a711] after transaction
13:03:18,263 DEBUG [main] jpa.JpaTransactionManager - Creating new transaction with name [com.mysystem.services.impl.UserLoginServiceImpl.login]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
13:03:18,263 DEBUG [main] jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl#1533badd] for JPA transaction
Hibernate:
/*
from
com.mysystem.domain.User u
where
u.userName = :userName
and u.password = :password */ select
user0_.id as id0_,
user0_.password as password0_,
user0_.userName as userName0_
from
Users user0_
where
user0_.userName=?
and user0_.password=? limit ?
13:03:18,374 TRACE [main] sql.BasicBinder - binding parameter [1] as [VARCHAR] - test
13:03:18,374 TRACE [main] sql.BasicBinder - binding parameter [2] as [VARCHAR] - test
13:03:18,379 DEBUG [main] jpa.JpaTransactionManager - Initiating transaction commit
13:03:18,379 DEBUG [main] jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl#1533badd]
13:03:18,379 DEBUG [main] jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl#1533badd] after transaction
Can you try this one.
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="createUser" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
I am using Spring + EclipseLink 2 to manage entity on a Derby database. Select object from db works fine but when I try to persist one, nothing happens. Program executes correctly and no exception are thrown. I probably did something wrong, as I'm not familiar with Spring, thanks for your comments and suggestions :)
The ServerDaoDb method :
#Transactional
public void addServer(Server server) {
EntityManager em = emf.createEntityManager();
emf.createEntityManager().persist(server);
em.close();
}
Application context is :
...
<tx:annotation-driven />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="SpringPratiquePU" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
Persistence.xml :
<persistence-unit name="SpringPratiquePU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>net.athom.spring.examples.models.eas.Server</class>
<class>net.athom.spring.examples.models.eas.Node</class>
<properties>
<property name="eclipselink.target-database" value="DERBY"/>
<property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/SpringPratique"/>
<property name="javax.persistence.jdbc.password" value="clem"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.user" value="clem"/>
</properties>
</persistence-unit>
</persistence>
The Debug Trace :
DEBUG JpaTransactionManager:365 - Creating new transaction with name [net.athom.spring.examples.service.impl.ServerManagerImpl.addServer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[EL Info]: 2010-10-29 15:33:27.443--ServerSession(14894886)--EclipseLink, version: Eclipse Persistence Services - 2.0.2.v20100323-r6872
[EL Info]: 2010-10-29 15:33:28.606--ServerSession(14894886)--file:/C:/netbeanProject/SpringPratique/src/_SpringPratiquePU login successful
15:33:28,893 DEBUG JpaTransactionManager:323 - Opened new EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl#1779885] for JPA transaction
15:33:28,951 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'transactionManager'
15:33:28,952 DEBUG JpaTransactionManager:286 - Found thread-bound EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl#1779885] for JPA transaction
15:33:28,953 DEBUG JpaTransactionManager:470 - Participating in existing transaction
15:33:29,266 DEBUG JpaTransactionManager:752 - Initiating transaction commit
15:33:29,267 DEBUG JpaTransactionManager:462 - Committing JPA transaction on EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl#1779885]
15:33:29,268 DEBUG JpaTransactionManager:548 - Closing JPA EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl#1779885] after transaction
15:33:29,308 DEBUG EntityManagerFactoryUtils:328 - Closing JPA EntityManager
Your error is here:
#Transactional
public void addServer(Server server) {
EntityManager em = emf.createEntityManager();
emf.createEntityManager().persist(server);
em.close();
}
Your are creating two different EntityManager instances, the em, which you are closing, and a new one at the next line with emf.createEntityManager() which you are using directly to persist your changes.
Try this:
#Transactional
public void addServer(Server server) {
EntityManager em = emf.createEntityManager();
em.persist(server);
em.close();
}
I guess that when you close your em instance, your changes are written to the DB, but, in case that they are not, you have to add em.flush(); right before closing the em instance.
I am not sure what exactly is wrong with your configuration (I guess EntityManager created manually can't participate in #Transactional transactions), but the typical JPA configuration in Spring looks like this, so you don't need to create EntityManager manually (also note the classname of the factory bean):
#PersistenceContext
private EntityManager em;
#Transactional
public void addServer(Server server) {
em.persist(server);
}
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="SpringPratiquePU" />
</bean>
Thx for your answers, both were very helpful. I ended up using LocalContainerEntityManagerFactoryBean, so I could inject the entity manager into my dao.
I added servlet-agent-2.5.6.jar on the lib folder and and pass VM options :
-javaagent:path/to/lib/ervlet-agent-2.5.6.jar
Then I modified ApplicationContext.xml :
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="SpringPratiquePU" />
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
And my dao:
...
#PersistenceContext
private EntityManager em;
#Transactional
public void addServer(Server server) {
em.persist(server);
}
Persistence and transactions work like a charm now !