First, we create classes that represent db entities, ok, done.
Let's say we use Hibernate session factory and JPA annotations.
Now we must create a DAO: getUserById, getAllUsers() etc.
What do you recommend about transaction management, session factory, how a good design to be made?
Make the DAO generic. See the Don't repeat the DAO article.
Transaction management should be spring-managed. Use a JpaTransactionManager. Transactions can be marked in two ways, and they should mark methods of the service classes, not the DAO:
using #Transactional on each transactional method (in combination with <tx:annotation-driven /> in applicationContext.xml)
using <tx:advice> and the appropriate <aop:config>
Use OpenEntityManagerInViewFilter or OpenEntityManagerInViewInterceptor in order to avoid LazyInitializationException
Read this for more details.
Related
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 ?
I have been googling for several hour now trying to find an example on how to write a service method that doesn't use Springs Hibernate Template while using a DAO interface. Something that is also confusing me is what happens when I put the #Transactional annotation in the service layer as opposed the DAO. Are the Service methods/DAO interfaces interchangeable?
Here is an example where the #Transactional is in the DAO
Here is one with the #Transactional in the Service Layer but using hibernate templates
Thanks for your help!
The Spring documentation recommends avoiding HibernateTemplate completely, and use the Hibernate API directly instead:
NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
also be coded in plain Hibernate style. Hence, for newly started
projects, consider adopting the standard Hibernate3 style of coding
data access objects instead, based on
SessionFactory.getCurrentSession().
And the #Transactional annotation should always be put on methods of the service layer. This is the layer that demarcates transactions.
Read http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#orm-session-factory-setup to understand how to setup a session factory. Once done, the session factory can be injected in your DAOs:
#Repository
public class MyDAO {
#Autowired
private SessionFactory sessionFactory;
...
}
I was going through the hibernate tutorial and noticed that in every dao you have to get session,begin transaction.Perform all operations and then commit
private void createAndStoreEvent(String title, Date theDate) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
//Perform operations...
session.getTransaction().commit();
}
Then i have noticed in a framework called Appfuse which uses hibernate have dao methods as shown below.I dont see the begintransaction and commit
public List<Person> findByLastName(String lastName) {
//begintransaction
return getHibernateTemplate().find("from Person where lastName=?", lastName);
//Commit
}
I wonder how appfuse is wrapping up the dao operations with session.beginTransaction() and session.getTransaction().commit();
By using this technique the programmer doesn't have to bother about hibernate transaction stuff.I want it in such a a way that even if dao methods are overridden the transaction wrapper code should automatically come.
I have tried passing dao to a decorator class and wrapping the dao method call inside decorator class.But since the dao interface methods will change,the idea dint worked.How exactly we can achieve this.
I don't know how AppFuse is doing it, but a very common way of introducing transaction management into the service layer of an application is by using Aspect Oriented Programming. If you're using the Spring Framework, this (from the manual) is a good reference.
HibernateTemplate is part of Spring. You can read more about it at this link. But starting with Spring 3.0, it's considered to be deprecated in favor of declarative transaction management.
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.