I am working on an application consisting of Spring and Hibernate frameworks. In one particular module, the application fetches the data from database (select queries). Along with the select queries, application also issues an update statement. After further debugging, I found that the update query is fired from some TransactionInterceptor.
I think, transaction interceptor is not required here as all are select queries. Can anyone please suggest me a way to disable/suppress this interceptor at runtime?
This problem might sound too abstract at first. However, I am new to this application and don't have much knowledge about it's architecture. If you need any configuration details, please let me know.
Thanks in advance.
Can you post your application-context.xml transaction management declarations part. Where the bean : org.springframework.jdbc.datasource.DataSourceTransactionManager is defined.
If the annotaion is not enabled you should activate it like this :
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="yourDataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
#Transactional(propagation = Propagation.NOT_SUPPORTED)
on your method will disable any Spring transactions on this proxy method call. Note that by disabling the transaction you also lose other benefits, like isolation.
However, the fact that you have an update query fired is NOT because of a transaction. You are likely to encounter a different error if you simply remove the transaction (likely stale object exception when hibernate tries to update outside of a transaction, or a malfunction of some module). Hibernate does not fire spurious updates, you should look for updates to the object in question during your transaction.
Here you have the JavaDoc of the interface org.hibernate.Session method clear() :
Completely clear the session. Evict all loaded instances and cancel all pending saves, updates and deletions. Do not close open iterators or instances of ScrollableResults
So when you use clear you will clear whole the Session. That ok, you will ask me : have I only one session per transaction ? I will answer you it's depends on your application HibernateTemplate configuration, if the HibernateTemplate.alwaysUseNewSession==true but the default value is false. The solution is to not intercepte your dao method with the Transaction Manager because it will be executed by default in a non Transactional Session.
Did you get a look to the Spring Framework AOP Proxy configuration. section 10.5 Declarative transaction management
I managed to suppress the update query by writing the following line in my DAO class (which was extending HibernateDAOSupport)
super.getSessionFactory().getCurrentSession().clear();
I just cleared the session as there was no update required while fetching the data and interceptor was updating the table.
Also, the original issue which I was facing is, the application was encountering org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1 from this update statement when it got executed twice (God knows why!).
Hence, we figured out that the update was never required and wanted to suppress it.
Can this fix have any consequences on the application? Is this the right way to do it? Will appreciate the inputs.
So your PlatformTransactionManager instance is HibernateTransactionManager. TransactionInterceptor will delegate the transaction handling to HibernateTransactionManager. All that means : all calls that you make to your data access methods annotated with #Transactional will be path throw spring AOP Proxy (which is a Proxy Design pattern).
If you don't use annotation-based and you have declared an AOP Proxy (search for aop:config tag in your ApplicationContext.xml).
So in the AOP Proxy configuration you will find the politic that your application use for intercepting data access methods and handling transactions.
For finding if you are using annotation-based you should know what is 'transactionAttributeSource' : AnnotationTransactionAttributeSource or AttributesTransactionAttributeSource ?
Related
I have a Spring-boot project where I have a service bean with 2 #Transactional annotated methods.
These methods do read-only JPA (hibernated) actions to fetch data from an HSQL file database, using both JPA repositories and lazy loaded getters in entities.
I also have a cli bean that handles commands (Using PicoCLI). From one of these commands I try to call both #Transactional annotated methods, but I get the following error during execution of the second method:
org.hibernate.LazyInitializationException - could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:602)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:217)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:581)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:148)
at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:188)
at java.util.Spliterators$IteratorSpliterator.estimateSize(Spliterators.java:1821)
at java.util.Spliterator.getExactSizeIfKnown(Spliterator.java:408)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
at <mypackage>.SomeImpl.getThings(SomeImpl.java:<linenr>)
...
If I mark the method that calls both #Transactional annotated methods with #Transactional itself, the code seems to work (due to there now only being 1 top level transaction I presume?).
I just want to find out why I cannot start multiple transactions in a single session or why the second transaction doesn't start a new session if there are none.
So my questions are:
Does this have to do with how hibernate starts a session, how transactions close sessions or anything related to the HSQL database?
Is adding an encompassing transaction the right way to fix the issue
or is this just fighting the symptom?
What would be the best way to be able to use multiple #Transactional annotated methods from one method?
EDIT: I want to make clear that I don't expose the entities outside of the transactional methods, so on the surface it looks to me like the 2 transactional methods should be working independently from one another.
EDIT2: for more clarification: the transactional methods need to be available in an api and the user of the api should be able to call multiple of these transactional methods, without needing to use transactional annotations and without getting the LazyInitializationException
Api:
public interface SomeApi {
List<String> getSomeList();
List<Something> getThings(String somethingGroupName);
}
Implementation:
public class SomeImpl implements SomeApi {
#Transactional
public List<String> getSomeList() {
return ...; //Do jpa stuff to get the list
}
#Transactional
public List<Something> getThings(String somethingGroupName) {
return ...; //Do other jpa stuff to get the result from the group name
}
}
Usage by 3rd party (who might not know what transactionality is):
public someMethod(String somethingGroupName) {
...
SomeApi someApi = ...; // Get an implementation of the api in some way
List<String> someList = someApi.someList();
if (someList.contains(somethingGroupName) {
System.out.println(someApi.getThings(somethingGroupName));
}
...
}
It seems that you are accessing some not initialized data from your entities after the transactions have ended. In that cases, the persistence provider may throw the lazyinitialization exception.
If you need to retrieve some information not eagerly loaded with the entities, you may use one of two strategies:
annotate the calling method also with #Transactional annotation, as you did: it does not start a new transaction for each call, but makes the opened transaction active until your calling method ends, avoiding the exception; or
make the called methods load eagerly the required fields USING the JOIN FETCH JPQL idiom.
Transaction boundaries requires some analysis of your scenario. Please, read this answer and search for better books or tutorials to master it. Probably only you will be able to define aptly your requirements.
I found that hibernate out of the box doesn't reopen a session and therefore doesn't enable lazy loading after the first transaction has ended, whether or not subsequent jpa statements are in a transaction or not. There is however a property in hibernate to enable this feature:
spring:
jpa:
properties:
hibernate.enable_lazy_load_no_trans: true
This will make sure that if there is no session, then a temp session will be created. I believe that it will also prevent a session from ending after a transaction, but I don't know this for sure.
Partial credit goes to the following answers from other StackOverflow questions:
http://stackoverflow.com/a/32046337/2877358
https://stackoverflow.com/a/11913404/2877358
WARNING: In hibernate 4.1.8 there is a bug that could lead to loss of data! Make sure that you are using 4.2.12, 4.3.5 or newer versions of hibernate. See: https://hibernate.atlassian.net/browse/HHH-7971.
I have an EntityManager and a JobDAO class which has many methods which use the EntityManager to select/update/delete/insert.
For some methods, I now am getting a javax.persistence.TransactionRequiredException: Executing an update/delete query ..
about not having a transaction.
I have a #Transactional annotation on the method calling the other methods.
I have now fixed it somewhat by using my own database connection for some of these commands, but I'd like to find the SQL that causes the problem.
One idea I have is to add a transaction checker method call to the end of each of the 20 methods that are suspicious. But I'd like to know whether you have a better idea to check on the EntityManager, for example by logging all SQL so I can find the last SQL where it stopped working.
See this post on SO for configuring the ORM provider (e.g. Hibernate, etc.) to log sql:
How to view the SQL queries issued by JPA?
In addition, you can programatically ask the EntityManager if it is currently in a transaction, see isJoinedToTransaction().
Also..., make sure that the class with the methods that have the #Transactional annotation is a Spring Bean, otherwise the annotation does nothing.
In addition you have to tell Spring to enable transaction management. This post will help you understand how to do that: https://www.baeldung.com/transaction-configuration-with-jpa-and-spring
How properly "lifecycle" of a Hibernate session under Spring should be done?
The SessionFactory is created automatically by Spring and is taking its DB connections from Glassfish connection pool. At the moment I am getting a Hibernate session via SessionFactory.getCurrentSession(). Then I start transaction, do the work and then commit() or rollback() at the end. Do I need to do any other actions like disconnect(), close(), flush() or any others at any time so connections would be properly returned back to the pool or is everything already automatically done by Spring?
With plenty of these methods it is a little confusing for me at the moment to understand when what should be done, maybe someone can point to right direction?
As SessionFactory is created automatically by Spring, Spring framework will take care of closing the connection.
Check out Spring Resource Management
If you want to check. You can check the log, if you are using logging for your app. It'll be like :
(main) INFO [AnnotationSessionFactoryBean] Closing Hibernate SessionFactory
I get following lines from this link
The main contract here is the creation of Session instances. Usually
an application has a single SessionFactory instance and threads
servicing client requests obtain Session instances from this factory.
The internal state of a SessionFactory is immutable. Once it is
created this internal state is set. This internal state includes all
of the metadata about Object/Relational Mapping.
Implementors must be threadsafe.
The policies about how the connection releases back to the connection pool have nothing to do with Spring .It is configured by Hibernate itself through the configuration parameter hibernate.connection.release_mode , which is identified by the enum in the org.hibernate.ConnectionReleaseMode
Start from version 3.1+ , the default value of the hibernate.connection.release_mode is auto which the corresponding ConnectionReleaseMode value depends on whether JTA or JDBC transaction is used. In case of JDBC transaction is used , it is set to ConnectionReleaseMode.AFTER_TRANSACTION (i.e after_transaction ).
The behaviour of ConnectionReleaseMode.AFTER_TRANSACTION is that : The connection will be returned to the connection pool after each transaction , that is by calling either transaction.commit() or transaction.rollback() , as well as calling session.close() and session.disconnect()
You can verify this behaviour in hibernate documentation Section 11.5.
Hope this link will guide you about session and transactions.
Then I start transaction, do the work and then commit() or rollback()
at the end. Do I need to do any other actions like disconnect(),
close(), flush() or any others at any time so connections would be
properly returned back to the pool or is everything already
automatically done by Spring?
As you call commit() on Transaction it will automatically closes the session, which ultimately calls close method on connection to return to it's pool.
When you are executing a hibernate query through SessionFactory.getCurrentSession() , Spring performs the necessary task of opening and closing the connection . The SessionFactory you are using in the spring config also calls the config.buildSessionFactory method internally .
Most of this happens in the implementations of the AbstractSessionFactoryBean. The closing of connecting is done by hibernate in the SessionFactoryImpl class using the statement settings.getConnectionProvider().close(); . In short , hibernate does everything for you . Spring just calls it's help when necessary.
I'm playing around with Spring + Hibernate and some "manual" transaction management with PostgreSQL
I'd like to try this out and understand how this works before moving to aop based transaction management.
#Repository
public class UserDAOImpl extends HibernateDaoSupport implements UserDAO {
#Override
public void saveUser(User u) {
Transaction tx = getSession().beginTransaction();
getHibernateTemplate().saveOrUpdate(u);
tx.rollback();
}
}
Calling saveUser here, I'd assume that saving a new User will be rolled back.
However, moving to a psql command line, the user is saved in the table.
Why isn't this rolled back, What do I have to configure to do transactions this way ?
Edit; a bit more debugging seems to indicate getHibernateTemplate() uses a different session than what getSession() returns (?)
Changing the code to
Transaction tx = getSession().beginTransaction();
getSession().persist(u);
tx.rollback();
and the transaction does get rolled back. But I still don't get why the hibernateTemplate would use/create a new session..
A couple of possibilities spring to mind (no pun intended):
a) Your JDBC driver defaults to autocommit=true and is somehow ignoring the beginTransaction() and rollback() calls;
b) If you're using Spring 3, I believe that SessionFactory.getSession() returns the Hibernate Session object wrapped by a Spring proxy. The Spring proxy is set up on the Session in part to handle transaction management, and maybe it's possible that it is interfering with your manual transaction calls?
While you can certainly use AOP-scoped proxies for transaction management, why not use the #Transactional(readOnly=false|true) annotation on your service layer methods? In your Spring config file for your service layer methods, all you need to do to make this work is to add
<tx:annotation-driven />
See chapters 10 and 13 of the Spring Reference Documentation on Transaction Management and ORM Data Access, respectively:
http://static.springsource.org/spring/docs/3.0.x/reference/index.html
Finally, if you're using Spring 3, you can eliminate references to the Spring Framework in your code by injecting the Spring-proxied SessionFactory bean into your DAO code - no more need to use HibernateDaoSupport. Just inject the SessionFactory, get the current Session, and use Hibernate according to the Hibernate examples. (You can combine both HibernateDaoSupport and plain SessionFactory-based Hibernate code in the same application, if required.)
If you see the JavaDoc for HibernateDaoSupport.getSession() it says it will obtain a new session or give you the one that is used by the existing transaction. In your case there isn't a transaction listed with HibernateDaoSupport already.
So if you use getHibernateTemplate().getSession() instead of just getSession(), you should get the session that is used by HibernateTemplate and then the above should work.
Please let me know how it goes.
EDIT:
I agree its protected...my bad. So the other option then is to keep the session thread bound which is usually the best practice in a web application. If HibernateDaoSupport is going to find a thread bound session then it will not create a new one and use the same one. That should let you do rollbacks.
I have an application that I am currently writing that will use Spring and Hibernate. In my services layer I have injected a DAO that will do some very basic CRUD-ing actions. For grins, I have created a method annotated as follows:
#Transactional(readOnly = false, propogation=Propogation.REQUIRES_NEW)
public void doSomeWork(Dao dao, Entity e){
//do some searching
dao.persist(e);
dao.findAll(Entity.clz);
}
The dao persist method looks like this:
public void persist(Entity e){
session.saveOrUpdate(e); //This has already been built using a SessionFactory
}
The dao findAll method looks like this
public void findAll(Class clz) {
session.createCriteria(clz).list();
}
Now, everything seems to run, OK. After I insert (persist) my object, I can see it using the findAll method (along with the new Primary Key ID that it was assigned by the Data Store), however, when the "doSomeWork" method completes, my data does not actually get persisted to the underlying datastore (Oracle 10g).
If, however, I remove the #Transactional annotations and use Hibernate's session.getTransaction().begin() and session.getTransaction().commit() (or rollback), the code works as I would anticipate.
So, my underlying question would then be: Does Hibernate not actually use Spring's transaction management for actual transaction management?
In my bean-config file I am declaring a TransactionManager bean, a SessionFactory bean, and I am also including in the config file.
What could I possibly be missing, aside for a better working-knowledge of Spring and Hibernate?
Don't forget to add <tx:annotation-driven> for #Transactional support
sounds like spring doesnt actually inject the transaction handling code.
do you have something like this in your config file, to tell spring where to look for annotated classes?
<beans xmlns:context="http://www.springframework.org/schema/context" ...
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd ..." >
...
<context:annotation-config/>
<context:component-scan base-package="mypackage.dao.impl"/>
<bean name="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>
what method do you use to obtain the session object from the session factory? Are you using openSession(), or getCurrentSession(), or perhaps something else? This matters because you need to session to be bound to the spring transaction (I doubt if openSession is good for your scenario)
I suggest that you use Spring's hibernateTemplate to invoke saveOrUpdate and persist, instead of using the session object. This way you are guaranteed that it will be bound to the transaction, and, as spring promises, you won't need to change the code if you ever change the transaction management strategy.
Ok, well, thanks to everyone who responded... it helped me to figure out what I am doing wrong...
In my overzealous "proof-of-concepting" it never really dawned on me what was going on until I realized that my "simple java class with a main method that will be doing all my work" isn't managed by spring, therefore no real transaction management. This will in no way behave as a product application would, being managed by an app-server with controller beans, services, etc.
Then it dawned on me... "services"... I'm going to have a services layer, that's where the transaction support will live. So, right as rain, I created a simple service bean (marked with #Transactional) and it works just as I would hope it would. So, I call methods on my service, which calls methods on my Dao and bam!!! it works.
Thanks again to everyone who helped me to come to this conclusion.