hibernate transaction not rolling back correctly - java

I have 2 tables, say Item and Property and a hibernate object mapped to both. The mapping for table Item to Property looks like
<set name="propertySet" cascade="all-delete-orphan">
<key column="item_id" not-null="true"/>
<one-to-many class="Property"/>
</set>
An item can have multiple properties. Everything like select, insert works properly. but when there is an error, the inserts to the property table do not rollback.
What happens is that if i am editing an item with N properties and enter an invalid value in a field, the next time I retrieve the item, it has 2*N properties.
Edit ---
What my class looks like is
#Autowired
SessionFactory sessionFactory
#Transactional
public void updateItem(Item i){
...
// The only 2 statements dealing with hibernate or session in this function
ItemModel im = sessionFactory.getCurrentSession().get(...);
sessionFactory.getCurrentSession().update(updatedItem);
...
}
I am using annotated transactions (#Transactional) with the spring framework and the lowest exception getting thrown is
Caused by: org.springframework.transaction.TransactionSystemException: Could not roll back Hibernate transaction; nested exception is org.hibernate.Tra
nsactionException: Transaction not successfully started
at org.springframework.orm.hibernate3.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:679)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:412)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:111)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
Caused by: org.hibernate.TransactionException: Transaction not successfully started
at org.hibernate.transaction.JDBCTransaction.rollback(JDBCTransaction.java:183)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:676)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:412)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:111)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
...
...
at org.apache.catalina.valves.SSLValve.invoke(SSLValve.java:113)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:894)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:719)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:2101)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)

Transactions don't "cascade". At the JDBC level, a transaction consists of:
Turning off autocommit
Executing some statements
Calling java.sql.Connection.commit() or java.sql.Connection.rollback().
If you're saying that some things are being committed and some are rolled back, then there's something wrong in your transaction management. Either autocommit is on or you actually have multiple calls to commit() happening.

Transactions are managed under the hood by Spring if you do the following: in your XML config, you need to 1) enable transactions, and 2) configure a transaction manager, as follows:
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mainSessionFactory" />
</bean>
Tx schemaLocation is http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"

Related

CMT JTA, but "no transaction is in progress"

I'm able to call entityManager.merge(obj), but not entityManager.flush().
I am getting "no transaction in progress".
My application context has:
<jee:jndi-lookup jndi-name="${persistenceEMFJndiServerName}"
id="entityManagerFactory" expected-type="javax.persistence.EntityManagerFactory" />
<bean id="entityManager"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
</bean>
My persistence unit says transaction-type="JTA"
and I'm loading it via
#PersistenceContext
private EntityManager entityManager;
I've tried a few things, like:
entityManager.joinTransaction(),
entityManager.getTransaction().begin()/.end(),
#Resource UserTransaction with BEAN transaction management, but it says I cant, with JTA. There's just no transaction going on.
My method has
#Transactional
#TransactionAttribute(TransactionAttributeType.REQUIRED)
and it's an EJB, so I'm getting pretty annoyed. CMT JTA is supposed to do transactions all by itself.
Turns out it wasn't a JPA/JBoss/etc. issue. It was because my thread ran in a camel context.
It took me a day of searching to find out:
Important
: One transaction is associated with a single thread of execution!
– If you use “seda”, “vm”, “jms” or any other protocol in your sub route which will process the exchange in an different thread, this execution will not be part of this transaction context!
FYI:
"asynchronous transactions in Camel 3.0.0"
I had my entityManager.merge/flush code in a thread. Hence, no transaction. Got rid of thread, and now it works fine.

Error while indexing in Hibernate Search (before transaction completion)

I am tired of banging my head around this problem So if anyone could suggest me where I am wrong I'll be grateful.
The problem is I am using Spring-Batch and Hibernate Full-Text Search in my Spring MVC project.So from the batch job Tasklet I am calling following code:
A a=aDao.merge(a);
b.setA(a);
bDao.save(b);
While doing the save update on these entites I am getting an exception and the stacktrace is as follows:
org.springframework.orm.hibernate3.HibernateSystemException: Error while indexing in Hibernate Search (before transaction completion); nested exception is org.hibernate.HibernateException: Error while indexing in Hibernate Search (before transaction completion)
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:690)
at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:147)
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:264)
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250)
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.hibernate.HibernateException: Error while indexing in Hibernate Search (before transaction completion)
at org.hibernate.search.backend.impl.EventSourceTransactionContext$DelegateToSynchronizationOnBeforeTx.doBeforeTransactionCompletion(EventSourceTransactionContext.java:175)
at org.hibernate.engine.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:543)
at org.hibernate.engine.ActionQueue.beforeTransactionCompletion(ActionQueue.java:216)
at org.hibernate.impl.SessionImpl.beforeTransactionCompletion(SessionImpl.java:571)
at org.hibernate.jdbc.JDBCContext.beforeTransactionCompletion(JDBCContext.java:250)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:138)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
... 21 more
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.search.util.HibernateHelper.unproxy(HibernateHelper.java:62)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.buildDocumentFields(DocumentBuilderIndexedEntity.java:394)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.buildDocumentFields(DocumentBuilderIndexedEntity.java:481)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.buildDocumentFields(DocumentBuilderIndexedEntity.java:481)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.getDocument(DocumentBuilderIndexedEntity.java:379)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.createAddWork(DocumentBuilderIndexedEntity.java:317)
at org.hibernate.search.engine.DocumentBuilderIndexedEntity.addWorkToQueue(DocumentBuilderIndexedEntity.java:295)
at org.hibernate.search.engine.WorkPlan$PerEntityWork.enqueueLuceneWork(WorkPlan.java:445)
at org.hibernate.search.engine.WorkPlan$PerClassWork.enqueueLuceneWork(WorkPlan.java:246)
at org.hibernate.search.engine.WorkPlan.getPlannedLuceneWork(WorkPlan.java:150)
at org.hibernate.search.backend.WorkQueue.prepareWorkPlan(WorkQueue.java:134)
at org.hibernate.search.backend.impl.BatchedQueueingProcessor.prepareWorks(BatchedQueueingProcessor.java:124)
at org.hibernate.search.backend.impl.PostTransactionWorkQueueSynchronization.beforeCompletion(PostTransactionWorkQueueSynchronization.java:89)
at org.hibernate.search.backend.impl.EventSourceTransactionContext$DelegateToSynchronizationOnBeforeTx.doBeforeTransactionCompletion(EventSourceTransactionContext.java:172)
... 27 more
I am not getting whats gone wrong.I am using org.springframework.orm.hibernate3.HibernateTransactionManager and my Spring version is 3.2 Hibernate core version is 3.6 final.
Note :This exception occurs often but When I create a new tables or use fresh db it works like charm and all modification/insertion are getting reflected properly in database.Can somebody explain me this behavior or Have i done something fishy.
Tell me if you need more details.
Thank you.
Code Update:
<batch:job-repository id="jobRepository"
data-source="myJNDI"
transaction-manager="transactionManager"
isolation-level-for-create="READ_COMMITTED"
max-varchar-length="2500"
lob-handler="defaultLobHandler"
/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="safeSessionFactory" />
</bean>
Like this I am configuring transaction manager in applicationContext.xml for Spring-Batch.And I have tried doing this with manually opening and closing session with manual commit of transaction but the exception remains same.And yes I have annotated my method as #Transactional.
I found the root cause of problem is Spring's Declarative Transaction Management.
Spring Batch in Action Reference:
Disable Spring’s declarative transactions for your batch application—Don’t use the tx:annotation-driven element or any XML
configuration related to declara- tive transaction management.
Be careful using propagation levels if declarative transactions are on—If you call trans- actional classes from a Spring Batch job,
Spring’s transaction propagation can interfere with the Spring Batch
transaction because of the propagation level. The REQUIRES_NEW
propagation level could typically cause problems because the
application code runs in its own transaction, independent of the
Spring Batch transaction.
The following are guidelines to avoid conflict between Spring Batch–managed and
Spring-managed transactions:

Can you explain why #Transactional not rolling back

I am trying to create two tables(ABC, XYZ) in Database. XYZ syntax intentionally has wrong syntax and is suppose to fail. The idea is that table creation of ABC should be rolled back when XYZ is tried. I am new to Spring Transaction and have searched around to come up with this simple example the logs seem to show that TransactionManager is rolling back but at the end I see that the table ABC is present in Database. Can anybody explain why #Transactional is not rolling back here...
package com.tango.db.dao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
public class DBDAO {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
#Transactional(rollbackFor = Exception.class)
public void createTables(){
jdbcTemplate.execute("CREATE TABLE ABC(ID NUMBER NOT NULL, NAME VARCHAR2(35), primary key(ID))");
jdbcTemplate.execute("CREATE TABLE XYZ(ID NUMBER NOT NULL, NAME VARCHAR2(35), UPDATE DATE(7), primary key(ID))");
}
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
DBDAO dbdao = (DBDAO)ctx.getBean("dbDAO");
dbdao.createTables();
}
}
spring-context.xml
<bean id="local.oracle.dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#10.211.55.6:1521:xe"/>
<property name="username" value="abc"/>
<property name="password" value="1234"/>
<property name="defaultAutoCommit" value="false"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="local.oracle.dataSource"/>
</bean>
<bean id="dbDAO" class="com.tango.db.dao.DBDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="local.oracle.dataSource"/>
</bean>
Following are the logs:
DEBUG SQLErrorCodeSQLExceptionTranslator - Translating SQLException with SQL state '42000', error code '904', message [ORA-00904: : invalid identifier
]; SQL was [CREATE TABLE XYZ(ID NUMBER NOT NULL, NAME VARCHAR2(35), UPDATE DATE(7), primary key(ID))] for task [StatementCallback]
DEBUG DataSourceTransactionManager - Initiating transaction rollback
DEBUG DataSourceTransactionManager - Rolling back JDBC transaction on Connection [jdbc:oracle:thin:#10.211.55.6:1521:xe, UserName=DBO, Oracle JDBC driver]
DEBUG DataSourceTransactionManager - Releasing JDBC Connection [jdbc:oracle:thin:#10.211.55.6:1521:xe, UserName=DBO, Oracle JDBC driver] after transaction
DEBUG DataSourceUtils - Returning JDBC Connection to DataSource
Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [CREATE TABLE XYZ(ID NUMBER NOT NULL, NAME VARCHAR2(35), UPDATE DATE(7), primary key(ID))]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00904: : invalid identifier
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:233)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:407)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:428)
at com.tango.db.dao.DBDAO.createTables(DBDAO.java:19)
at com.tango.db.dao.DBDAO$$FastClassByCGLIB$$112527a.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at com.tango.db.dao.DBDAO$$EnhancerByCGLIB$$7b0ac5f7.createTables(<generated>)
at com.tango.db.dao.DBDAO.main(DBDAO.java:25)
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 com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.sql.SQLSyntaxErrorException: ORA-00904: : invalid identifier
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:837)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:445)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:191)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:523)
at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:193)
at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:999)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1315)
at oracle.jdbc.driver.OracleStatement.executeInternal(OracleStatement.java:1890)
at oracle.jdbc.driver.OracleStatement.execute(OracleStatement.java:1855)
at oracle.jdbc.driver.OracleStatementWrapper.execute(OracleStatementWrapper.java:304)
at org.apache.commons.dbcp.DelegatingStatement.execute(DelegatingStatement.java:264)
at org.apache.commons.dbcp.DelegatingStatement.execute(DelegatingStatement.java:264)
at org.springframework.jdbc.core.JdbcTemplate$1ExecuteStatementCallback.doInStatement(JdbcTemplate.java:421)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:396)
... 16 more
In your case the transaction boundary is not entirely up to Spring. If you dig a bit deeper into Oracle documentation, it defines the transaction boundary as follow:
A transaction begins with the first executable SQL statement. A
transaction ends when it is committed or rolled back, either
explicitly with a COMMIT or ROLLBACK statement or implicitly when a
DDL statement is issued.
http://docs.oracle.com/cd/B28359_01/server.111/b28318/transact.htm#i6564
CREATE TABLE is a DDL (Data Definition Language) statement. Hence when you issued the first CREATE TABLE, Oracle took it as an implicit end-of-transaction. Therefore when your second CREATE TABLE is issued and failed, it's too late to revert the first one.
This is because a create table is a DDL (data definition language) statement and only DML (data modification language) statements are rolledback. There is an implicit commit at every DDL statement, so they cannot be rolledback.
To be complete, DML statements are: insert, update and delete.
Looks like you're using JDK proxies but do not have any interface declared for Spring to use to create a proxy against. DBDAO needs to be an interface that has the createTables method on it, so Spring has something to create the runtime implementation of that includes the transaction code.

hibernate doesn't issue update after flush

I'm using hibernate 3.2.7 (same problem on 3.2.5) with spring 3.0.1, all deployed on weblogic 10.3 and with an Oracle 10g database. I'm using JTA transaction management and the transaction is distributed (it is actually started and ended in another application, this code is just in between).
The configuration used by hibernate is declared in my persistence.xml and is the following:
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WeblogicTransactionManagerLookup"/>
<property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory"/>
<property name="hibernate.current_session_context_class" value="jta"/>
<property name="hibernate.connection.release_mode" value="auto"/>
The spring configuration regarding the transaction manager is the following:
<!-- Instructs Spring to perfrom declarative transaction managemenet on annotated classes -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
<!-- Data about transact manager and session factory -->
<bean id="txManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
<property name="transactionManagerName" value="javax.transaction.TransactionManager"/>
<property name="defaultTimeout" value="${app.transaction.timeOut}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- persistence unit is missing jta data source so that application server is not
creating EntitiyManagerFactory, spring will create its own LocalContainerEntityManagerFactoryBean overriding data source-->
<property name="dataSource" ref="myDataSource"/>
<!-- specific properties like jpa provider and jpa provider properties are in persistance unit -->
<property name="persistenceUnitName" value="my.persistence.unit"/>
</bean>
<!-- define data source in application server -->
<jee:jndi-lookup id="myDataSource" jndi-name="${db.jndiName}"/>
I'm using a generic CrudDao with an update method that looks like this:
public void update(Object entity) {
//entityManager injected by #PersistenceContext
entityManager.merge(entity);
entityManager.flush();
}
public Object getById(Object id, Class entityClass) throws PersistenceException{
return (Object)entityManager.find(entityClass, id);
}
UPDATED: added the getById method.
The code that does not work as expected looks like this:
MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne, idOther);
// till now was null
myObj.setSomeDateAttr(someDate);
genericDao.update(myObj);
MyObject myObjFromDB = genericDao.getById(myObj.getId(), MyObject.class);
The result is that if I print myObj.getSomeDateAttr() it returns me the value of someDate, if I print myObjFromDB.getSomeDateAttr() it still has null.
I've tried changing the update method to:
org.hibernate.Session s = (org.hibernate.Session) entityManager.getDelegate();
s.evict(entity);
s.update(entity);
s.flush();
And it still doesn't work.
When turning on the show_sql flag of hibernate I don't see any update occurring when doing flush nor when I query the entity manager for the object with the same id. The selects are all visible.
UPDATE:
At the end of the transaction the update is actually called and everything is written to the db. So my problem is "just" during the transaction.
I'm afraid the problem may be linked with the configuration of the transaction manager on spring and on hibernate.
Hope that someone can help me as I have already lost a day and a half with no luck.
You need to look at the hibernate merge behaviour closely. As per documentation
if there is a persistent instance with the same identifier currently
associated with the session, copy the state of the given object onto
the persistent instance
if there is no persistent instance currently associated with the session, try to load it from the database, or create a new persistent instance
the persistent instance is returned
the given instance does not become associated with the session, it
remains detached
As per your statement on the sql queries in log, it look like
MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne, idOther); returning the persistent object but when you modify it(becomes dirty) and call merge method, new state is copied to the current persistent object in session. If you see third point merge returns persistent object which is actually new manageable persistent object which you need to use in subsequent operations.
When you call find method hibernate returns the persistent object in session and not maneagable persistent object thats why you dont find the changes in object return by find.
To fix your problem change the reurn type of update method
public Object update(Object entity) {
//entityManager injected by #PersistenceContext
return entityManager.merge(entity);
}
and in service you need to use as below
MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne, idOther);
// till now was null
myObj.setSomeDateAttr(someDate);
//You can use myObj as well instead myNewObj
MyObject myNewObj= genericDao.update(myObj);
//No need to call get
//MyObject myObjFromDB = genericDao.getById(myObj.getId(), MyObject.class);
System.out.println("Updated value:"+myNewObj.getSomeDateAttr());
Have a look at this artical as well.

Spring/Hibernate Truncate/Delete all rows from a table - Transaction issues

I have a Camel project and after we create a controll bean we want to clean up a DB log table. SO each time we run the application we TRUNCATE a table called agent orders. This is setup in an Enity object as a named query.
#NamedNativeQuery(name="cleanOrderTable", query="TRUNCATE agent_orders",resultClass= AgentOrderEntity.class)
The code that calls this query looks like:
#Component("mgr")
public class Controller{
#PersistenceContext(unitName="camel")
private EntityManager em;
.......
#Transactional
public void clearHistoricalOrders() throws Exception{
Query query = em.createNamedQuery("cleanOrderTable");
query.executeUpdate();
}
}
Call the clear history method we get an error javax.persistence.TransactionRequiredException: Executing an update/delete query
I have tried everything, UserTransaction, em.getTransaction().begin - nothing works. Any idea how I can run this query?
We have the following tran manager setup in our app context.xml:
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:dataSource-ref="dataSource">
<property name="entityManagerFactory" ref="emFactory" />
</bean>
Try debugging and check whether your controller is proxied and whether there's transaction-related code executed before your method. Try enabling database server logs to check what queries really get executed.
Make sure you don't have any ServletFilters that set-up a read-only transaction prior to getting to your Controller.
Make sure your entity manager is the one that's passed to the transaction manager.
Also, I've found some info advising against using #PersistenceContext in servlets: http://weblogs.java.net/blog/ss141213/archive/2005/12/dont_use_persis.html
Hope this helps!
I'd try executing the query with a TransactionTemplate just to check that the #Transactional annotation really isn't having an effect.
Also, what's up with resultClass= AgentOrderEntity.class? Why does a query that truncates a table need to return something?

Categories