I'm trying to use Multithread in my app to do some tasks that take some minutes to complete.
The idea is that I have n number of objects so I want those to be processed in parallel and without making the user (web app) wait for them to be completed (as it takes several minutes). Also in other case (when the amount of object is one), I want to wait until the process is done so the user can see the result.
But I'm having some issues.
So my code is:
RunSomeTaskServiceImpl:
public class RunSomeTaskServiceImpl extends CommonService implements RunSomeTaskService{
#Async
#Override
public Future<Response> doTasks(Student student) {
Response response = new Response();
//do Tasks
return new AsyncResult<Response>(response);
}
}
RunSomeTaskService:
public interface RunSomeTaskService{
public Future<Response> doTasks(Student student);
}
StudentServiceImpl:
#Autowired
RunSomeTaskService runSomeTaskService;
#Override
Transactional
public Response save(StudentBO[] students) throws Exception {
...
for (StudentBO student : students) {
....
Future<Response> response = runSomeTaskService.doTasks(student);
if(students.size() == 1){
return response.get();
}
}
....
}
So when there is more than one student, I get the error:
12:17:44.040 [DEMO-4] DEBUG o.h.r.t.b.j.i.JdbcResourceLocalTransactionCoordinatorImpl - JDBC transaction marked for rollback-only (exception provided for stack trace)
java.lang.Exception: exception just for purpose of providing stack trace
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.markRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:265) [hibernate-core-5.0.6.Final.jar:5.0.6.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:156) [hibernate-core-5.0.6.Final.jar:5.0.6.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) [hibernate-core-5.0.6.Final.jar:5.0.6.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231) [hibernate-core-5.0.6.Final.jar:5.0.6.Final]
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65) [hibernate-core-5.0.6.Final.jar:5.0.6.Final]
at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:581) [spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) [spring-tx-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) [spring-tx-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485) [spring-tx-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291) [spring-tx-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) [spring-tx-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:108) [spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionAspectSupport$CompletableFutureDelegate$1.get(AsyncExecutionAspectSupport.java:237) [spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]
12:17:44.043 [DEMO-4] DEBUG o.s.o.h.HibernateTransactionManager - Initiating transaction rollback after commit exception
org.hibernate.AssertionFailure: null id in com.app.model.FieldValue entry (don't flush the Session after an exception occurs)
And when there is just one:
org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions. Collection : <unknown>
Collection contents: [[]]
at org.hibernate.collection.internal.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:627)
at org.hibernate.event.internal.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:46)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
at org.hibernate.event.internal.AbstractVisitor.process(AbstractVisitor.java:126)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:293)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:648)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:640)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:635)
at com.app.dao.CommonDaoImpl.addOrUpdate(CommonDaoImpl.java:28)
at com.app.services.ExtractDataServiceImpl.doExtraction(ExtractDataServiceImpl.java:361)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:108)
at org.springframework.aop.interceptor.AsyncExecutionAspectSupport$CompletableFutureDelegate$1.get(AsyncExecutionAspectSupport.java:237)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Student model
package com.app.model;
// Generated 18-jul-2018 15:27:32 by Hibernate Tools 5.2.10.Final
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
/**
* Student generated by hbm2java
*/
#Entity
#Table(name = "student", catalog = "school_db", uniqueConstraints = #UniqueConstraint(columnNames = "code"))
public class Student implements java.io.Serializable {
private Integer id;
private String name;
private Grade grade;
private Set<Subject> subjects = new HashSet<Subject>(0);
public Student() {
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "grade")
public Grade getGrade() {
return this.grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "student")
public Set<Subject> getSubjects() {
return this.subjects;
}
public void setSubjects(Set<Subject> subjects) {
this.subjects = subjects;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "student")
public Set<Subject> getSubjects() {
return this.subjects;
}
}
spring-config.xml file
<?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:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
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/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config />
<!-- <context:component-scan base-package="com.app.controller, com.app.security" /> -->
<context:component-scan base-package="com.app.controller" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<mvc:annotation-driven />
....
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.app.model.Student</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
...
So could you please help me to avoid this issues?
Related
I am not able to auto-create table from maven spring mvc.
I was doing a spring mvc project using maven. By far i have got no errors but when i am trying to create table in my database using applicationconfig.xml it is not working. i have searched over the internet but my applicationconfig.xml seems fine to me. I have got no errors. Still the table is not created..
applicationconfig.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"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
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-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<bean id="entityManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.milan.entities" /><!--scans model/entity/domain(name 3 but same) and registers-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<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/inventorymanagement" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManager" />
</bean>
<tx:annotation-driven />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
User Class
package com.milan.entities;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
public class User implements Serializable{
#Id
#Column(name = "USER_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long userId;
#Column(name = "USERNAME")
private String userName;
#Column(name = "PASSWORD")
private String password;
#Column(name = "IS_ENABLEd")
private boolean isEnabled;
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isIsEnabled() {
return isEnabled;
}
public void setIsEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
}
}
There is no error while running the program however the table is not created automatically.
Put #Entity on your User class, if the table still not created try putting below annotations on the class:
#Entity
#Table(name = "`user`")
Could be happening because User is a reserve word in DB.
Consider this example in which I have created two JPA entities and used Spring Data JPA repositories to perform simple CRUD -
import java.sql.Timestamp;
import javax.persistence.Version;
#MappedSuperclass
public class AbstractValueObject {
#Id
#GeneratedValue
private Long id;
#Version
#Column(name = "time_stamp")
private Timestamp version;
public Long getId() {
return id;
}
#Override
public String toString() {
if (id == null) {
return "";
}
return id.toString();
}
}
#Entity
#Table(name = "demo")
public class Demo extends AbstractValueObject {
private String name;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "demo")
private List<Owner> owners;
public Demo() {
owners = new ArrayList<>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Owner> getOwners() {
return Collections.unmodifiableList(owners);
}
public void addOwner(Owner owner) {
this.owners.add(owner);
owner.setDemo(this);
}
public void addAllOwners(List<Owner> owners) {
this.owners.addAll(owners);
for (Owner owner : owners) {
owner.setDemo(this);
}
}
public void update(Demo demo) {
this.setName(demo.getName());
this.owners.clear();
this.addAllOwners(demo.getOwners());
}
}
#Entity
#Table(name = "owner")
public class Owner extends AbstractValueObject {
private String attribute;
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#JoinColumn(name = "demo_id", nullable = false)
private Demo demo;
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
public Demo getDemo() {
return demo;
}
public void setDemo(Demo demo) {
this.demo = demo;
}
}
After that, I have created a JPA repository for the Demo entity, extending from JpaRepository -
import org.springframework.data.jpa.repository.JpaRepository;
public interface DemoRepository extends JpaRepository<Demo, Long> {}
Corresponding service implementation -
import javax.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
public class DemoServiceImpl implements DemoService {
#Resource
private DemoRepository demoRepository;
#Override
#Transactional
public Demo create(Demo demo) {
return demoRepository.save(demo);
}
#Override
#Transactional
public Demo update(long id, Demo demo) {
Demo dbDemo = demoRepository.findOne(id);
if (dbDemo == null) {
return demo;
}
dbDemo.update(demo);
return dbDemo;
}
#Transactional
public void testRun() {
Owner owner = new Owner();
owner.setAttribute("attribute");
Demo demo = new Demo();
demo.setName("demo");
demo.addOwner(owner);
this.create(demo);
demo.setName("another");
this.update(demo.getId(), demo);
}
}
persistence.xml file -
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="2.1">
<persistence-unit name="jpa-optimistic-locking" transaction-type="RESOURCE_LOCAL">
</persistence-unit>
</persistence>
Spring app-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:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx" 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-4.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.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.0.xsd">
<context:component-scan base-package="com.keertimaan.example.jpaoptimisticlocking" />
<jpa:repositories base-package="com.keertimaan.example.jpaoptimisticlocking.repository" />
<bean id="demoService" class="com.keertimaan.example.jpaoptimisticlocking.service.DemoServiceImpl" />
<!-- JPA/Database/Transaction Configuration -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
<property name="user" value="root" />
<property name="password" value="admin123" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="2" />
<property name="acquireIncrement" value="1" />
<property name="maxStatements" value="5" />
<property name="idleConnectionTestPeriod" value="500" />
<property name="maxIdleTime" value="1000" />
<property name="loginTimeout" value="800" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="jpa-optimistic-locking" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</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="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
Now whenever I try to update an entity like this on Windows 7 -
public class App {
public static void main(String[] args) {
DemoService demoService = (DemoService) SpringHelper.INSTANCE.getBean("demoService");
demoService.testRun();
}
}
I get an exception like this -
Exception in thread "main"
org.springframework.orm.ObjectOptimisticLockingFailureException:
Object of class
[com.keertimaan.example.jpaoptimisticlocking.domain.Demo] with
identifier [4]: optimistic locking failed; nested exception is
org.hibernate.StaleObjectStateException: Row was updated or deleted by
another transaction (or unsaved-value mapping was incorrect) :
[com.keertimaan.example.jpaoptimisticlocking.domain.Demo#4] at
org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:228)
at
org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:155)
at
org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:519)
at
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy31.testRun(Unknown Source) at
com.keertimaan.example.jpaoptimisticlocking.App.main(App.java:9)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or
deleted by another transaction (or unsaved-value mapping was
incorrect) :
[com.keertimaan.example.jpaoptimisticlocking.domain.Demo#4] at
org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2541)
at
org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3285)
at
org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3183)
at
org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3525)
at
org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:159)
at
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
at
org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at
org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at
org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
at
org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at
org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
at
org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
at
org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
... 9 more
If I run the same example in Ubuntu, then I get no exception at all and my application completes successfully. Why is that?
I am using Windowsw 7 64-bit edition -
OS Name: Microsoft Windows 7 Enterprise
OS Version: 6.1.7601 Service Pack 1 Build 7601
and my Ubuntu version is 12.04.5 64-bit edition.
JDK used in Windows: jdk7 update 75
JDK used in Ubuntu: jdk7 update 51
MySQL Server version in Windows: 5.6.23-log MySQL Community Server (GPL)
MySQL Server version in Ubuntu: 5.5.41-0ubuntu0.12.04.1 (Ubuntu)
I have a feeling that this is related to the timestamp precision of MySQL 5.6. MySQL 5.6.4 introduced microsecond precision, which will cause a version mismatch, and the locking will fail.
This is not related to your problem directly but in a highly concurrent environment you should not use timestamp as your version as two entity might have the same time! It's better to use a long/int version like below-
#Version
long version;
Also from design perspective please make your super class abstract as well. Can you check if changing these solves your problem?
I'm trying to write a simple Spring app and I'm having trouble getting the Spring Repository to work right. I'm getting a NullPointerException at com.impetus.kundera.query.KunderaQuery.initEntityClass(KunderaQuery.java:390).
The exception is ultimately caused by collectionRepository.findAll().
Full stack trace:
java.lang.NullPointerException
at com.impetus.kundera.query.KunderaQuery.initEntityClass(KunderaQuery.java:390)
at com.impetus.kundera.query.KunderaQuery.postParsingInit(KunderaQuery.java:353)
at com.impetus.kundera.query.QueryResolver.getQueryImplementation(QueryResolver.java:80)
at com.impetus.kundera.persistence.PersistenceDelegator.getQueryInstance(PersistenceDelegator.java:557)
at com.impetus.kundera.persistence.PersistenceDelegator.createQuery(PersistenceDelegator.java:527)
at com.impetus.kundera.persistence.EntityManagerImpl.createQuery(EntityManagerImpl.java:379)
at com.impetus.kundera.persistence.EntityManagerImpl.createQuery(EntityManagerImpl.java:717)
at com.impetus.kundera.persistence.EntityManagerImpl.createQuery(EntityManagerImpl.java:704)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
at com.sun.proxy.$Proxy33.createQuery(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:471)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:264)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:358)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:343)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:105)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy35.findAll(Unknown Source)
at com.example.spring.controller.CollectionController.listCollections(CollectionController.java:29)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
I've debugged it nearly as far as I can go and there's a few causes for concern. Going back to the EntityManagerImpl on line 704 the CriteriaQueryTranslator translates the CriteriaQuery to SELECT FROM CollectionEntity null.
This query obviously has problems. So going deeper into the CriteriaQueryTranslator.translate method (line 122):
builder.appendAlias(from.getAlias() != null ? from.getAlias() : select.getAlias());
The from.getAlias() returns null, therefore the select.getAlias() is appended to the builder (which is also null). So the alias is what is causing the weird JPQL syntax.
So is this a bug in Kundera or do I have some Spring configuration wrong?
The collectionRepository.findAll() in the controller is what generates this error.
Here's all my configuration and subject java files:
CollectionController:
import com.example.spring.hibernate.CollectionEntity;
import com.example.spring.repositories.CollectionRepository;
import com.example.spring.services.CollectionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.annotation.Resource;
#Controller
public class CollectionController {
#Autowired
private CollectionRepository collectionRepository;
#RequestMapping(value="/collections", method= RequestMethod.GET)
public String listCollections(ModelMap model) {
model.addAttribute("collection", new CollectionEntity());
// THE ERROR HAPPENS HERE (collectionRepository.findAll())
model.addAttribute("collections", collectionRepository.findAll());
return "collections";
}
}
CollectionRepository:
import com.example.spring.hibernate.CollectionEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CollectionRepository extends JpaRepository<CollectionEntity, Long> {
}
CollectionEntity:
import javax.persistence.*;
import java.util.Date;
#Entity(name="collection")
#Table(name = "collection", schema = "", catalog = "mydb")
public class CollectionEntity {
#Id
#Column(name = "collection_id")
private int collectionId;
#Basic
#Column(name = "collection_name")
private String collectionName;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "collection_type_id")
private CollectionTypeEntity collectionType;
#Column(name = "active")
private boolean active;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at")
private Date createdDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated_at")
private Date updatedDate;
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Date getUpdatedDate() {
return updatedDate;
}
public void setUpdatedDate(Date updatedDate) {
this.updatedDate = updatedDate;
}
public int getCollectionId() {
return collectionId;
}
public void setCollectionId(int collectionId) {
this.collectionId = collectionId;
}
public String getCollectionName() {
return collectionName;
}
public void setCollectionName(String collectionName) {
this.collectionName = collectionName;
}
public CollectionTypeEntity getCollectionType() {
return collectionType;
}
public void setCollectionTypeId(CollectionTypeEntity collectionType) {
this.collectionType = collectionType;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
persistence.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="maria_pu">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<class>com.example.spring.hibernate.CollectionEntity</class>
<class>com.example.spring.hibernate.CollectionTypeEntity</class>
<properties>
<property name="kundera.client.lookup.class" value="com.impetus.client.rdbms.RDBMSClientFactory" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.connection.driver_class" value="org.mariadb.jdbc.Driver" />
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/mydb" />
<property name="hibernate.connection.username" value="root" />
<property name="hibernate.connection.password" value="" />
<property name="hibernate.current_session_context_class" value="thread"/>
</properties>
</persistence-unit>
</persistence>
web.xml:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring Hello World Application</display-name>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
and finally the dispatcher.servlet.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.example.spring" />
<jpa:repositories base-package="com.example.spring.repositories"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="maria_pu"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
As I said I'm new to Spring so I may just be missing some configuration parameters. Any help is greatly appreciated!
I'm currently facing a problem when trying to save to my database using the persist method from an entitymanager. When executing it, it does not produce an exception but it doesn't save the object to my database. Reading objects that were inserted manually does work.
GenericDAOImpl
package be.greg.PaymentDatabase.DAO;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;
public abstract class GenericDaoImpl<T> implements GenericDao<T> {
#PersistenceContext
protected EntityManager em;
private Class<T> type;
String entity;
#SuppressWarnings({ "unchecked", "rawtypes" })
public GenericDaoImpl() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class) pt.getActualTypeArguments()[0];
}
#Override
public long countAll(final Map<String, Object> params) {
final StringBuffer queryString = new StringBuffer(
"SELECT count(o) from ");
queryString.append(type.getSimpleName()).append(" o ");
// queryString.append(this.getQueryClauses(params, null));
final Query query = this.em.createQuery(queryString.toString());
return (Long) query.getSingleResult();
}
#Override
#Transactional
public T create(final T t) {
this.em.persist(t);
return t;
}
#Override
public void delete(final Object id) {
this.em.remove(this.em.getReference(type, id));
}
#Override
public T find(final Object id) {
return (T) this.em.find(type, id);
}
#Override
public T update(final T t) {
return this.em.merge(t);
}
#SuppressWarnings("unchecked")
#Override
#Transactional
public List<T> findAll() {
Query query = em.createQuery("select x from " + getEntityName() + " x");
return (List<T>) query.getResultList();
}
public String getEntityName() {
if (entity == null) {
Entity entityAnn = (Entity) type.getAnnotation(Entity.class);
if (entityAnn != null && !entityAnn.name().equals("")) {
entity = entityAnn.name();
} else {
entity = type.getSimpleName();
}
}
return entity;
}
}
AuthorizationV2DAOImpl
package be.greg.PaymentDatabase.DAO;
import org.springframework.stereotype.Repository;
import be.greg.PaymentDatabase.model.Authorization;
#Repository
public class AuthorizationV2DAOImpl extends GenericDaoImpl<Authorization>
implements AuthorizationV2DAO {
}
AuthorizationService
package be.greg.PaymentDatabase.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import be.greg.PaymentDatabase.DAO.AuthorizationV2DAOImpl;
import be.greg.PaymentDatabase.model.Authorization;
#Service
public class AuthorizationService {
#Autowired
private AuthorizationV2DAOImpl authorizationDAO;
public Authorization getAuthorization(int id){
return authorizationDAO.find(id);
}
public List<Authorization> getAllAuthorizations(){
return authorizationDAO.findAll();
}
public void createAuthorization(Authorization authorization)
{
authorizationDAO.create(authorization);
}
}
Authorization
package be.greg.PaymentDatabase.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "authorization")
public class Authorization {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(length = 32, nullable = false)
private String clientId;
#Column(length = 32, nullable = false)
private String acquiringInstitutionId;
#Column(length = 32, nullable = false)
private String cardAcceptorTerminalId;
#Column(length = 32, nullable = false)
private String merchantTransactionTimestamp;
#Column(length = 32, nullable = false)
private String industry;
#Column(length = 32, nullable = false)
private String accountNumber;
#Column(nullable = false)
private boolean maskedAccount;
#Column(length = 11, nullable = false)
private int expiryMonth;
#Column(length = 11, nullable = false)
private int expiryYear;
#Column(length = 32, nullable = false)
private String securityCode;
#Column(length = 32, nullable = false)
private String line1;
#Column(length = 32, nullable = true)
private String line2;
#Column(length = 32, nullable = true)
private String city;
#Column(length = 32, nullable = true)
private String countrySubdivision;
#Column(length = 32, nullable = false)
private String postalCode;
#Column(length = 32, nullable = false)
private String country;
#Column(length = 32, nullable = false)
private String clientReference;
#Column(length = 32, nullable = false)
private String currency;
#Column(length = 11, nullable = false)
private int value;
#Column(length = 32, nullable = false)
private String ecommerceIndicator;
#Column(length = 32, nullable = false)
private String transactionId;
#Column(length = 32, nullable = false)
private String token;
Constructor, getters and setters ...
spring-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:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:component-scan base-package="be.greg.PaymentDatabase" />
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="jdbcPropertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:project.properties" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"
p:username="${jdbc.username}" />
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>classpath*:META-INF/persistence.xml</value>
</list>
</property>
<property name="defaultDataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="persistenceUnitName" value="entityManager" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
persistance.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="entityManager"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<validation-mode>NONE</validation-mode>
<class>be.greg.PaymentDatabase.model.Authorization</class>
<class>be.greg.PaymentDatabase.model.AuthorizationResponse</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
</persistence>
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/paymentdatabase?zeroDateTimeBehavior=convertToNull</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping class="be.greg.PaymentDatabase.model.Authorization" />
<mapping class="be.greg.PaymentDatabase.model.AuthorizationResponse" />
</session-factory>
</hibernate-configuration>
runnable main class
package be.greg.PaymentDatabase.Tests;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import be.greg.PaymentDatabase.model.Authorization;
import be.greg.PaymentDatabase.service.AuthorizationService;
#Component
public class HibernateDatabaseTest {
public static void main(String[] args) {
#SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext(
"/spring-context.xml");
HibernateDatabaseTest p = context.getBean(HibernateDatabaseTest.class);
Authorization authorization = new Authorization("000091095650", "1340",
"001", "2012-01-06T09:30:47Z", "MOTO", "4417122900000002",
false, 12, 12, "382", "100", null, null, null, "33606", "USA",
"12345678901234567", "USD", 1540, "5",
"Q0JLSkIyODlWMVBaTDRURFhYV0Y=", "Q0JLSkIyODlWMVBaTDRURFhYV0Y=");
p.start(authorization);
}
#Autowired
private AuthorizationService authorizationService;
private void start(Authorization authorization) {
authorizationService.createAuthorization(authorization);
List<Authorization> list = authorizationService.getAllAuthorizations();
for (Authorization authorizations : list) {
System.out.println(authorizations.getClientId());
}
}
}
When I add em.flush in the GenericDaoImpl class right after the persist, it gives following exception
Exception in thread "main" javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
at com.sun.proxy.$Proxy24.flush(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
at com.sun.proxy.$Proxy20.flush(Unknown Source)
at be.greg.PaymentDatabase.DAO.GenericDaoImpl.create(GenericDaoImpl.java:50)
at be.greg.PaymentDatabase.service.AuthorizationService.createAuthorization(AuthorizationService.java:35)
at be.greg.PaymentDatabase.Tests.HibernateDatabaseTest.start(HibernateDatabaseTest.java:36)
at be.greg.PaymentDatabase.Tests.HibernateDatabaseTest.main(HibernateDatabaseTest.java:27)
So I assume it has to do something with the transaction or perhaps the fact that one hasn't been made. But I have not found the cause for this problem yet
Thanks in advance!
Edit
These are the dependencies for Spring and Hibernate that I use
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.4.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.4.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
Before persisting and merging objects you should open the transaction and then commit it.
em.getTransaction.begin();
em.persist(obj);
em.getTransaction().commit();
Try replacing import javax.transaction.Transactional; with import org.springframework.transaction.annotation.Transactional;
I'm thinking that if you have to use the spring transctional, configure the entity manager in the spring itself like link this.
Or you have to use manual transaction management like the Answer given by Alex.
I have used Java EE 6 before and I have created a connection resource (pooled) on the server and then bound it to a JNDI name which I have referenced inside the jta-data-source element tag in the Persistence.xml file.
Now I use Spring 3 and I have a hard time understanding all the different beans that I need to set up and why need to do so. EJB 3 automatically wrap the methods in transactions. In Spring it seems like you need to configure a transaction manager, however I don't know. Need explanation.
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myapp" expected-type="javax.sql.DataSource"/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="packagesToScan" value="com.myapp.app"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.PostgreSQL82Dialect
</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
I understand the jndi lookup for the data source, however I don't understand the rest thourougly. I am not able to insert/persist objects with this configuration.
I need an explanation on how Spring 3 differs from Java EE 6 in this area, and how to do it the same way.
After thinking a little more on your original question, I'd like to add:
Spring doesn't automatically wrap every method with a Transaction. You have to tell Spring where you want your Transactional Boundaries to be. You do that with either XML config or by using the #Transactional annotation.
You should have a look at where you should declare transactions - here and here.
You should have a look at Spring's Transaction Management - here.
You should have a look at Transaction Config - here.
I am still of the opinion that your config is good and that the trouble you are having lies within the beans attempting to use your EntityManager. I renew my request for you to post that, as I'm certain I could get you going if I could see it.
I've looked at your configuration and I can't find anything wrong with it. As an example, I will provide (at the bottom) something I have in a working application right now.
I don't believe your problem is within your configuration, but in your usage of the configured beans. If you could provide code showing me (us) how you are interacting with your EntityManager, I could probably identify your issue(s).
I'll provide you with working examples of a Entity, Repository, and XML Config to try and help you locate your issue:
Spring Config (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:p="http://www.springframework.org/schema/p"
xmlns:jee="http://www.springframework.org/schema/jee"
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-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.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">
<context:annotation-config />
<context:component-scan base-package="com.company.app.dao" />
<context:component-scan base-package="com.company.app.service" />
<jee:jndi-lookup id="dataSource"
jndi-name="jdbc/Test" />
<bean id="jpaDialect"
class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<bean id="entityManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="packagesToScan" value="com.company.app.model" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManager" />
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true" />
</beans>
Model
import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
#Entity
public class User {
#Id
private String id = UUID.randomUUID().toString();
#Column
#Length(min = 3, max = 25)
private String name;
#OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true)
#JoinColumn(name = "userId", nullable = false)
private Set<Contact> contacts = new HashSet<Contact>();
public UUID getId() {
return UUID.fromString(id);
}
public void setId(UUID id) {
this.id = id.toString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Contact> getContacts() {
return contacts;
}
public void setContacts(Set<Contact> contacts) {
this.contacts = contacts;
}
public void addContact(Contact contact) {
this.contacts.add(contact);
}
public void removeContact(Contact contact) {
this.contacts.remove(contact);
}
}
Repository
import com.company.app.model.User;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaQuery;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
#Repository
public class UserDao {
#PersistenceContext
private EntityManager em;
#Transactional(propagation = Propagation.REQUIRED)
public void createUser(User user) {
em.persist(user);
}
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public User readUserById(UUID id) {
CriteriaQuery<User> query = em.getCriteriaBuilder().createQuery(User.class);
query.where (em.getCriteriaBuilder().equal(query.from(User.class).get("id"),id.toString()));
return em.createQuery(query).getSingleResult();
}
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public Set<User> readAll() {
CriteriaQuery<User> query = em.getCriteriaBuilder().createQuery(User.class);
query.from(User.class);
return new HashSet<User>(em.createQuery(query).getResultList());
}
#Transactional(propagation = Propagation.REQUIRED)
public User update(User user) {
return em.merge(user);
}
#Transactional(propagation = Propagation.REQUIRED)
public void delete(User user) {
em.remove(user);
}
}