I have an application using Spring 3.2.3 and Hibernate 4.2.1.Final. I made some configurations and the app works pretty well on the test environment, using HSQLDB, etc.
But when the app is deployed it almost works fine. The entity is created but never persisted. I can see the JPA logs:
Hibernate: select nextval ('TASK_SEQ')
But an insert never appears =(
Using the configuration:
<?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"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<context:component-scan base-package="br.com.company" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="spring_pu" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<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" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="spring_pu" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>br.com.company.core.entities.Task</class>
<properties>
<property name="hibernate.connection.autocommit" value="true" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.connection.url" value="jdbc:postgresql://127.0.0.1:5432/companyDB" />
<property name="hibernate.connection.user" value="postgres" />
<property name="hibernate.connection.password" value="*****" />
</properties>
</persistence-unit>
</persistence>
The entity:
@Entity
@Table(name = "TASK")
public class Task implements Serializable {
private static final long serialVersionUID = -6262731134419520342L;
@Id
@Column(name = "ID")
@GeneratedValue(generator = "TASK_SEQ", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "TASK_SEQ", name = "TASK_SEQ")
private long id;
@Column(name = "DESCRIPTION")
private String description;
@Column(name = "FINISHED")
private boolean fininshed;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "FINISH_DATE")
private Date finishDate;
//getters and setter below
}
And finally the service:
@Service
public class TaskService {
@PersistenceContext
private EntityManager entityManager;
@Transactional(propagation = Propagation.REQUIRED)
public void createTask(Task task) {
<b>//invoked method</b>
entityManager.persist(task);
}
As I said, there are no exceptions being thrown but the entity is not persisted like it is at the tests. Thank you!
Edit: I also tried to remove the persistence.xml content into a spring datasource and the problem is still the same:
<?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"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://127.0.0.1:5432/KCILDS" />
<property name="username" value="postgres" />
<property name="password" value="*****" />
</bean>
<context:component-scan base-package="br.com.company" />
<bean id="myEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="br.com.company.core.entities" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEntityManagerFactory" />
</bean>
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>
SOLUTION:
I give up the xml configuration. Nothing seems to work with it anymore. Reading more about the tendencies and a lot of configuration I ended up trying successfully a java config and with a few more adjustments will fit perfectly. See below:
@Configuration
@EnableTransactionManagement
@ComponentScan("br.com.company")
public class PersistenceJPAConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(this.directDataSource());
factoryBean.setPackagesToScan(new String[] { "br.com.company" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
factoryBean.setJpaVendorAdapter(vendorAdapter);
factoryBean.setJpaProperties(this.additionlProperties());
return factoryBean;
}
private Properties additionlProperties() {
Properties properties = new Properties();
properties.put("database", "POSTGRESQL");
properties.put("databasePlatform", "org.hibernate.dialect.PostgreSQLDialect");
properties.put(Environment.SHOW_SQL, true);
properties.put(Environment.FORMAT_SQL, true);
return properties;
}
// now reasearch how to make it an environment configuration
// @Bean
// public DataSource dataSource() {
// JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
// jndiDataSourceLookup.setResourceRef(true);
// return jndiDataSourceLookup.getDataSource("jdbc/mybank");
// }
@Bean
public DataSource directDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://127.0.0.1:5432/MyBank");
dataSource.setUsername("postgres");
dataSource.setPassword("*******");
return dataSource;
}
@Bean //still trying to make a JTA Transaction
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(this.entityManagerFactoryBean().getObject());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
First, you should enable a PersistenceAnnotationBeanPostProcessor
bean, like so:
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
As documented in Spring 3.1.x doc, section 14.5.2 :
Spring can understand @PersistenceUnit and @PersistenceContext annotations both at field and method level if a PersistenceAnnotationBeanPostProcessor is enabled.
Another thing, make sure your TaskService
is scanned. According to the posted Spring configuration file, only the package br.com.company
is scanned so TaskService
should be under that package.
EDIT
You should use @Transactional
for public
methods that implement an interface
. By default, advice annotation are implemented by Spring via simple Java Proxy
, which requires an interface.
As documented in section 8.1.3 AOP Proxies :
Spring AOP defaults to using standard J2SE dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.
Of course, this also implies that TaskService
should be referenced by other beans via that interface alone.
I've faced an issue similar to the one described. I found the problem in incorrect usage of @Transactional notation, in particular I've wrongly used javax.transaction.Transactional instead of org.springframework.transaction.annotation.Transactional
Take a look to the imports of your "@Service".
A detailed description of the difference can be found here at javax.transaction.Transactional vs org.springframework.transaction.annotation.Transactional
As TaskService
is defined as a service therefore Spring container won't maintain transactions for CRUD operations. You should delegate CRUD operations to another bean -normally I suffix them with Managers.
So this will be the full hierarchy of transaction workflow:
TaskManager
@Resource(name = "taskManager")
TaskManager taskManager;
3 . Inject EntityManager
etc in newly created Manager class
4 . Put all CRUD methods in the manager class
5 . Call these methods from Service
Call hierarchy: Service -> Manager -> DAO -> Entity Manager
Now you should be able to persist your entity.
I would first doublecheck some obvious stuff: Was the Task type is of br.com.company.Task, not other java api Task ?
If you're still having the same problem, maybe something is wrong with your transaction management. Try flushing the entityManager after you persists. Typically entityManager should automatically flush at the end of transactions:
@Transactional(propagation = Propagation.REQUIRED)
public void createTask(Task task) {
entityManager.persist(task);
entityManager.flush(task);
}
If you do have a problem with transaction manager, try instead of specifying datasource inside persistence.xml, create it on spring xml and use dataSource property of JpaTransactionManager
Also set following log4j logger to see transaction start/end and SQL issued by hibernate:
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.transaction=DEBUG
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.