Issue with projection when using #Lob and #Query - spring-data-jpa

Entity:
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer price;
#Lob
private String description;
}
Interface for Projection:
public interface NameAndDesc {
String getAlias();
String getDesc();
}
Repository:
public interface ItemRepository extends JpaRepository<Item, Long> {
#Query(value = "SELECT NAME AS ALIAS, DESCRIPTION AS DESC FROM ITEM WHERE ID IS :#{#id}",nativeQuery = true)
NameAndDesc findNameAndDesc(#Param("id") Long id);
}
When I try to call .getDesc() on the query above, I get this exception:
java.lang.IllegalArgumentException: Projection type must be an interface!
at org.springframework.util.Assert.isTrue(Assert.java:118)
at org.springframework.data.projection.ProxyProjectionFactory.createProjection(ProxyProjectionFactory.java:100)
at org.springframework.data.projection.SpelAwareProxyProjectionFactory.createProjection(SpelAwareProxyProjectionFactory.java:45)
at org.springframework.data.projection.ProjectingMethodInterceptor.getProjection(ProjectingMethodInterceptor.java:131)
at org.springframework.data.projection.ProjectingMethodInterceptor.invoke(ProjectingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.ProxyProjectionFactory$TargetAwareMethodInterceptor.invoke(ProxyProjectionFactory.java:245)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy105.getDesc(Unknown Source)
at com.example.demo.DemoApplicationTests.contextLoads(DemoApplicationTests.java:18)
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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
When I remove the "#Lob" annotation from "description" the projection is working without any problem.
It seems that the problem is the CLOB what returns from the DB. When I change the projection interface method to clob "java.sql.Clob getDesc();" it seems to start working again, but not the best solution.
Is it right behaviour when using projections, like this?
I found a somewhat similar issue when it was a bug in ProxyProjectionFactory:
Issue with projection in SpringDataRest and #Lob attribute

The idea behind a projection is to limit the columns returned and (ideally requested) from the database.
There isn't much conversion support build in because this is normally handled by JPA but this doesn't happen because you are using a native query.
I therefore see two options how to solve the issue:
Convert the LOB into a VARCHAR2 or similar in the database.
How this is done depends on your database.
This answer seems to work for SQL Server.
I'm sure you'll find an alternative for whatever database you are using.
Get JPA back in the game by using a JPQL query.
That should be database independent but I assume you had a reason for using a native query, to begin with.

One way around this is to use the Spring Content community project. This project allows you to associate content with Spring Data entities. The content is managed separately leaving only "managed" content-related metadata on the Entity. This won't mess your projections. Think Spring Data but for Content (or Unstructured data).
This is pretty easy to add to your existing projects. I am not sure if you are using Spring Boot, or not. I'll give a non-spring boot example:
pom.xml
<!-- Java API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-jpa</artifactId>
<version>0.5.0</version>
</dependency>
<!-- REST API (if desired)-->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest</artifactId>
<version>0.5.0</version>
</dependency>
Configuration
#Configuration
#EnableJpaStores
#Import("org.springframework.content.rest.config.RestConfiguration.class")
public class ContentConfig {
// schema management
//
#Value("/org/springframework/content/jpa/schema-drop-mysql.sql")
private Resource dropContentTables;
#Value("/org/springframework/content/jpa/schema-mysql.sql")
private Resource createContentTables;
#Bean
DataSourceInitializer datasourceInitializer() {
ResourceDatabasePopulator databasePopulator =
new ResourceDatabasePopulator();
databasePopulator.addScript(dropContentTables);
databasePopulator.addScript(createContentTables);
databasePopulator.setIgnoreFailedDrops(true);
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource());
initializer.setDatabasePopulator(databasePopulator);
return initializer;
}
}
To associate content, add Spring Content annotations to your account entity.
Item.java
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer price;
// replace #Lob field with
#ContentId
private String contentId;
#ContentLength
private long contentLength = 0L;
// if you have rest endpoints
#MimeType
private String mimeType = "text/plain";
}
Create a "store":
ItemContentStore.java
#StoreRestResource(path="itemsContent)
public interface ItemContentStore extends ContentStore<Item, String> {
}
This is all you need to create REST endpoints # /itemsContent. When your application starts, Spring Content will look at your dependencies (seeing Spring Content JPA/REST), look at your ItemContentStore interface and inject an implementation of that interface for JPA. It will also inject a #Controller that forwards http requests to that implementation. This saves you having to implement any of this yourself whch I think is what you are after.
So...
For to access content through a Java API, auto-wire ItemContentStore and use its methods.
Or to access content through a REST API:
curl -X POST /itemsContent/{itemId}
with a multipart/form-data request will store the image in the database and associate it with the account entity whose id is itemId.
curl /itemsContent/{itemId}
will fetch it again and so on...supports full CRUD.
There are a couple of getting started guides here. The reference guide is here. And there is a tutorial video here. The coding bit starts about 1/2 way through.
HTH

Related

NullPointer while using JPA EntityManager in a ThredPoolExecutor

I'm implementing a JavaEE8 application using CDI and running on an Open Liberty (v20.0.0.4). The application has a event-triggered job, which runs some code in an separate thread using the ThreadPoolExecutor like this:
#Singleton
public class MyJobExecutorService {
#PostConstruct
public void init() {
thredPoolExecutor = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
}
public void runJob(MyConfigs configs) {
thredPoolExecutor.submit(() -> new MyJobRunnable(configs).run());
}
}
The job gets data from the underlying sql database using an EntityManager, which is injected in the data access class and produced like following. My querys are written using querydsl (which should not be relevant).
public class EntityManagerProducer {
#PersistenceContext(unitName = "my-unit")
private EntityManager entityManager;
#Produces
#Dependent
public EntityManager getEntityManager() {
return entityManager;
}
}
My persistence.xml looks like this:
<persistence ...>
<persistence-unit name=my-unit">
<jta-data-source>jdbc/datasource</jta-data-source>
</persistence-unit>
</persistence>
I have no issues accessing the database from the main thred, but the job throws a NullPointerException with the following stacktrace (and no further information):
com.ibm.ws.jpa.management.JPATxEntityManager.getEMInvocationInfo(JPATxEntityManager.java:213)
com.ibm.ws.jpa.management.JPATxEntityManager.getEMInvocationInfo(JPATxEntityManager.java:164)
com.ibm.ws.jpa.management.JPAEntityManager.getDelegate(JPAEntityManager.java:402)
com.querydsl.jpa.impl.JPAProvider.getTemplates(JPAProvider.java:61)
com.querydsl.jpa.impl.JPAQuery.<init>(JPAQuery.java:48)
com.querydsl.jpa.impl.JPAQueryFactory.query(JPAQueryFactory.java:138)
com.querydsl.jpa.impl.JPAQueryFactory.select(JPAQueryFactory.java:81)
com.querydsl.jpa.impl.JPAQueryFactory.selectFrom(JPAQueryFactory.java:111)
my.application.MyRepository.getAll(DataAccess.java:67)
sun.reflect.GeneratedMethodAccessor1888.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.MyRepository$Repository$Serializable$925348889$Proxy$_$$_WeldClientProxy.getAll(UnknownSource)
sun.reflect.GeneratedMethodAccessor1887.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.DataAccess$587668909$Proxy$_$$_WeldClientProxy.getAllData(UnknownSource)
my.application.job.MyDefaultJob.runJob(MyDefaultJob.java:50)
sun.reflect.GeneratedMethodAccessor1886.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.job.MyJob$588111896$Proxy$_$$_WeldClientProxy.runJob(UnknownSource)
my.application.job.MyJobExecutorService$MyRunnable.run(MyJobExecutorService.java:59)
my.application.job.MyJobExecutorService.lambda$runJob$0(MyJobExecutorService.java:36)
my.application.job.MyJobExecutorService$$Lambda$280/00000000A8128A20.run(UnknownSource)
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:823)
Why am I getting this exception and how can I fix this? Activating the jpa an concurrency features in the server.xml of the application server didnt help. Thanks a lot.
Enabling the concurrent-1.0 feature alone doesn't do anything unless you are using the managed resources that it provides which capture the context of the application component (such as its java:comp name space and so forth) and makes it available when running the tasks that are submitted to it.
If you must use a ThreadPoolExecutor in order to manipulate its queue in some way beyond enforcing concurrency constraints (ManagedExecutorService can impose concurrency constraints via a configurable concurrencyPolicy), the simplest way to continue using a ThreadPoolExecutor is by supplying it with a ManagedThreadFactory,
#PostConstruct
public void init() {
ManagedThreadFactory threadFactory = InitialContext.doLookup(
"java:comp/DefaultManagedThreadFactory");
thredPoolExecutor = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(),
threadFactory);
}
ManagedThreadFactory captures the context that is present on the thread from which it is initially looked up. You'll need to decide if there is a better place for it than your init() method based on what context you want it to provide to your ThreadPoolExecutor tasks.
You should also be aware that any use of ThreadPoolExecutor (even in combination with a ManagedThreadFactory or ContextService) bypasses use of the Liberty global thread pool.

Spring Data JPA: Work with Pageable but with a specific set of fields of the entity

I am working with Spring Data 2.0.6.RELEASE.
I am working about pagination for performance and presentation purposes.
Here about performance I am talking about that if we have a lot of records is better show them through pages
I have the following and works fine:
interface PersonaDataJpaCrudRepository extends PagingAndSortingRepository<Persona, String> {
}
The #Controller works fine with:
#GetMapping(produces=MediaType.TEXT_HTML_VALUE)
public String findAll(Pageable pageable, Model model){
Through Thymeleaf I am able to apply pagination. Therefore until here the goal has been accomplished.
Note: The Persona class is annotated with JPA (#Entity, Id, etc)
Now I am concerned about the following: even when pagination works in Spring Data about the amount the records, what about of the content of each record?.
I mean: let's assume that Persona class contains 20 fields (consider any entity you want for your app), thus for a view based in html where a report only uses 4 fields (id, firstname, lastname, date), thus we have 16 unnecessary fields for each entity in memory
I have tried the following:
interface PersonaDataJpaCrudRepository extends PagingAndSortingRepository<Persona, String> {
#Query("SELECT p.id, id.nombre, id.apellido, id.fecha FROM Persona p")
#Override
Page<Persona> findAll(Pageable pageable);
}
If I do a simple print in the #Controller it fails about the following:
java.lang.ClassCastException:
[Ljava.lang.Object; cannot be cast to com.manuel.jordan.domain.Persona
If I avoid that the view fails with:
Caused by:
org.springframework.expression.spel.SpelEvaluationException:
EL1008E:
Property or field 'id' cannot be found on object of type
'java.lang.Object[]' - maybe not public or not valid?
I have read many posts in SO such as:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to
I understand the answer and I am agree about the Object[] return type because I am working with specific set of fields.
Is mandatory work with the complete set of fields for each entity? Should I simply accept the cost of memory about the 16 fields in this case that never are used? It for each record retrieved?
Is there a solution to work around with a specific set of fields or Object[] with the current API of Spring Data?
Have a look at Spring data Projections. For example, interface-based projections may be used to expose certain attributes through specific getter methods.
Interface:
interface PersonaSubset {
long getId();
String getNombre();
String getApellido();
String getFecha();
}
Repository method:
Page<PersonaSubset> findAll(Pageable pageable);
If you only want to read a specific set of columns you don't need to fetch the whole entity. Create a class containing requested columns - for example:
public class PersonBasicData {
private String firstName;
private String lastName;
public PersonBasicData(String firstName, String lastName) {
this.firstName = fistName;
this.lastName = lastName;
}
// getters and setters if needed
}
Then you can specify query using #Query annotation on repository method using constructor expression like this:
#Query("SELECT NEW some.package.PersonBasicData(p.firstName, p.lastName) FROM Person AS p")
You could also use Criteria API to get it done programatically:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<PersonBasicData> query = cb.createQuery(PersonBasicData.class);
Root<Person> person = query.from(Person.class);
query.multiselect(person.get("firstName"), person.get("lastName"));
List<PersonBasicData> results = entityManager.createQuery(query).getResultList();
Be aware that instance of PersonBasicData being created just for read purposes - you won't be able to make changes to it and persist those back in your database as the class is not marked as entity and thus your JPA provider will not work with it.

JPA Query gets transformed [duplicate]

This question already has answers here:
Spring Boot + JPA : Column name annotation ignored
(13 answers)
Closed 6 years ago.
I have a repository method like
#Query("from Application app where app.id.hostId = :hostId")
List<Application> getApplicationsByApplicationId(#Param("hostId") String hostId);
And my domain class reads something like
public class Application {
#EmbeddedId
Composite id;
...
...
#Embeddable
public static class Composite implements java.io.Serializable {
#Column(name = "id")
private String id;
#Column(name = "hostId")
private String hostId;
....
Somewhere down the processing chain, hostIdstring gets transformed to host_id, So I get an error like
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'application0_.host_id' in 'field list'.
I am trying to migtate an existing hibernate / JPA layer into Spring Boot JPA.
Any pointers will be greatly appreciated.
This is caused by the Hibernate naming strategy.
The default strategy transforms camel case in Java to _ in database.
If you don't want this behavior use JPA default. You can set it in application.properties:
spring.jpa.hibernate.naming_strategy: org.hibernate.cfg.EJB3NamingStrategy
Use:
#Column(name = "hostid")
notice that all are lowercase.

Spring data elastic search findAll with OrderBy

I am using spring data's elastic search module, but I am having troubles building a query. It is a very easy query though.
My document looks as follows:
#Document(indexName = "triber-sensor", type = "event")
public class EventDocument implements Event {
#Id
private String id;
#Field(type = FieldType.String)
private EventMode eventMode;
#Field(type = FieldType.String)
private EventSubject eventSubject;
#Field(type = FieldType.String)
private String eventId;
#Field(type = FieldType.Date)
private Date creationDate;
}
And the spring data repository looks like:
public interface EventJpaRepository extends ElasticsearchRepository<EventDocument, String> {
List<EventDocument> findAllOrderByCreationDateDesc(Pageable pageable);
}
So I am trying to get all events ordered by creationDate with the newest event first. However when I run the code I get an exception (also in STS):
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property desc found for type Date! Traversed path: EventDocument.creationDate.
So it seems that it is not picking up the 'OrderBy' part? However a query with a findBy clause (eg findByCreationDateOrderByCreationDateDesc) seems to be okay. Also a findAll without ordering works.
Does this mean that the elastic search module of spring data doesn't allow findAll with ordering?
Try adding By to method name:
findAllByOrderByCreationDateDesc

Hibernate Envers - org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update

I am using Hibernate Envar for Audit purpose.
Here is my code and configuration
hibernate.cfg.xml file configuration
<!-- Audit -->
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-insert"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-update"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-delete"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-update"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-remove"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-collection-recreate"/>
One Sample Entity Annoted with #Audited
#Entity
#Table(name = "Users")
#Audited
public class User extends GenericDomain implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(length=100)
private String name;
#Column(length=60)
private String username;
#Column(length=130)
private String password;
// Getter and setter with more fields
}
I have created a RevistionEntity to log audit for logged in user, for whom we are logging audit as
#Entity
#Table(name = "REVISIONS")
#RevisionEntity(CustomRevisionListener.class)
public class CustomRevisionEntity {
#Id
#GeneratedValue
#RevisionNumber
private int id;
#RevisionTimestamp
private long audit_timestamp;
private String username;
private Long userid;
// Getter and Setter
}
Here is my listener class
public class CustomRevisionListener implements RevisionListener {
public void newRevision(Object revisionEntity) {
CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity;
revision.setUsername("username"); //for testing
}
}
For Insert/Delete it works fine.
But for Update query it is giving following exception as
[ERROR] [http-8080-1 06:05:26] (JDBCExceptionReporter.java:logExceptions:101) Duplicate entry '1085-3' for key 1
[ERROR] [http-8080-1 06:05:26] (AbstractFlushingEventListener.java:performExecutions:324) Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:179)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
at org.hibernate.envers.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:157)
at org.hibernate.envers.synchronization.AuditProcess.beforeCompletion(AuditProcess.java:164)
at org.hibernate.transaction.JDBCTransaction.notifyLocalSynchsBeforeTransactionCompletion(JDBCTransaction.java:274)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:140)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy106.deleteSaleRecord(Unknown Source)
at org.commission.controller.salerecord.SaleRecordController.delete(SaleRecordController.java:753)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.commission.util.SessionFilter.doFilter(SessionFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.BatchUpdateException: Duplicate entry '1085-3' for key 1
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2018)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 46 more
Here is my generic update code for all entities
public E update(E entity) {
getSession().update(entity);
return entity;
}
Unfortunately without the full stacktrace and the SQL definition of the tables, its hard to say whats happening here. These are the things I would check:
Constraints/PK on the audit tables? - is it possible your primary key is missing the revision number AND revision type - I had this occur because an update and a delete happened in the same session for a particular entity (I think it had something to do with a Cascade operation, but I cannot recall now), and I was expecting the revision number + PK of the entity table to be enough to uniquely identify each row in the audit tables.
Remember that by default deleted entities only contain the revision number, revision type, and the ID/PK of the original entity. If you have a NOT NULL constraint on the audit table, that could cause the failure. You can work around that by setting the org.hibernate.envers.store_data_at_delete property to true.