Hibernate template close transaction - java

I run following working code:
Session session = null;
try {
SessionFactory sessionFactory = new Configuration().configure()
.buildSessionFactory();
session = sessionFactory.openSession();
String id = (String) FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap().get(
"storeId");
Transaction t = session.beginTransaction();
stores = getStores();
for (Store store : stores) {
if (store.getId() == Integer.parseInt(id)) {
session.delete(store);
}
}
t.commit();
} catch (Exception e) {
} finally {
session.close();
}
}
When i try redo this code to use Hibernate template, i go unending request to DB:
HibernateTemplate template = new HibernateTemplate();
template .setSessionFactory(sessionFactory);
stores = template.find("from Stores");
for (Store store : stores) {
if (store.getId() == Integer.parseInt(id)) {
template.delete(store);
}}
Looks like transaction is not closed.
How could I close transaction this case? And is it will better at all to use Hibernate template approach instead of session approach showed at first code?

You didn't say it, but I assume you're referring to the HibernateTemplate class in the Spring Framework. HibernateTemplate participates in Spring transactions, but it doesn't manage them on its own. Spring provides a lot of ways to manage transactions both programmatically and declaratively. If you're just experimenting, you can use the TransactionTemplate class to quickly test it out. For larger projects, you should consider using declarative transaction management because it simplifies your code, although it's a little trickier to set up initially.
As for whether or not the HibernateTemplate approach is better than managing your sessions manually, I'd say anything that reduces boilerplate code is a good thing, so yes. This is especially crucial on big projects. However, depending on your project, HibernateTemplate might not even be necessary. It was originally created to work around some deficiencies in Hibernate 2.x, but many of those deficiencies were eliminated in Hibernate 3. So before adopting it, read the HibernateTemplate JavaDoc for a discussion of the advantages.

Related

"javax.persistence.TransactionRequiredException: no transaction is in progress", even with #Transactional; possible to implicitly manage Transactions?

I'm upgrading an old system that is a batch job that uses Camel Spring Main to continue running, so that it can basically loop and query a database every few seconds, and then process those records. It uses Spring for configuration, but doesn't use Spring Boot. It was on Camel 2.x and I'm having to upgrade it to Camel 3.14. Also upgrading from Spring 4 to 5 and Hibernate 4 to 5.
After those upgrades, when I run it, I'm getting this TransactionRequiredException. Have found that a fair amount here; I have added the #Transactional to the method that does the update where the error occurs, but that made no difference.
Found another answer that says you also need context:component-scan in appContext.xml, which I do have.
This answer suggested adding a hibernate property, hibernate.allow_update_outside_transaction = true, which I tried in my app-confix.xml, but it didn't work.
This answer said to add the following code, which I did, and which did fix it:
protected static void storeObject(Object object) throws DAOException {
Transaction tx = null;
try {
Session session = Helper.getHibernateSession();
session.saveOrUpdate(object);
tx = session.beginTransaction();
session.flush();
tx.commit();
} catch (HibernateException he) {
if(tx != null){
tx.rollback();
}
throw new DAOException(he);
}
}
But to add this to every method that does an update seems like a lot of boilerplate, repeated code. Is there any way to implicitly do basic Transactions all the time? I tried configuring #Transactional and #EnableTransactionManagement and configured the supporting #Beans in a #Configuration class, by following the outline here, but still got the TransactionRequiredException: no transaction in progress error.
One article said #Transactional is only available in Spring Boot: is this true?

System design to support database connectivity

I am trying to develop a forum system as a part of a university assignment,
which contains a database connectivity part.
I am writing the server in java and decided to use hibernate as an ORM tool to save and load from the data base.
My question is not about the syntax, but about the design of the entire system regarding the database.
Who should be in charge of creating a session and commit transactions? should I make a singleton which recive an object and save it to the database and use this singelton in every setter/constructor of the different classes?
should each change in a memory object be commited directly or should I commit only every few changes? (and if so what is the best way to do this?)
Ideally, a framework should do that for you. Using Spring, for example, you could simply mark methods of Spring beans transactional using an annotation, and the session and transaction handling would be done by Spring:
#Autowired
private SessionFactory sessionFactory;
#Transactional
public void foo() {
Session session = sessionFactory.getCurrentSession();
// do some work with the session
}
instead of
private SessionFactory sessionFactory;
public void foo() {
Session sess = sessionFactory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
// do some with the session
tx.commit();
}
catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
}
finally {
sess.close();
}
}
You should neither commit after each change, nor commit every few changes. You should commit atomic, coherent changes. That's the whole point of transactions:being able to go from a coherent state of your database to another coherent state of your database.
For example If posting a message to a topic forum consists in
persisting a message instance
incrementing the messageCount field of the forum
creating a notification for the topic poster
then these three changes should be in a single transaction, to make sure you don't end up with the message being persisted, but the messageCount not being incremented.
I suggest you leave creating and committing transactions to the container, unless you are sure you want to do it yourself. In this case you can use JTA, and use Container Managed Transactions (CMT). Also remember to avoid entitymanager-per-operation antipattern. To learn more read about Transactions and Concurrency and decide yourself what suit you the best.
Take a look at the DAO (Data Access Object) pattern. It will help to provide a pattern which will help you to encapsulate your data access.
http://en.wikipedia.org/wiki/Data_access_object
Also, this page does a great job:
Data access object (DAO) in Java
As for the second question, the answer entirely depends on your requirements. Usually you want to commit at least once per user interaction. That might be the result of several in-memory changes. It is definitely easier to commit after each entity is changed.

Same Code wrapping for different dao methods

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.

hibernate jpa: Session is closed!

Application is based on Spring 2.5.5 and hibernate 3.2.0 GA.
I have the following method in my DAO that gets MessageEntities attached to the specified User:
public MessageEntity findByUserId(int userId) {
List<MessageEntity> result = (List<MessageEntity>) em.createNamedQuery(MessageEntity.Q_BY_USER_ID).setParameter("userId", userId).getResultList();
if (!result.isEmpty()) {
return result.get(0);
} else {
return null;
}
}
I need to call this method from my integration test to check whether system's behaviour is valid. As long as this method is not transactional, all I get is org.hibernate.SessionException: Session is closed!. The easiest way to avoid this is to mark findByUserId method with #Transactional(readOnly = true). But as I understand, transaction management should be the duty of service tier to avoid unnecessary transactions creation. So, my question is: how can I properly get away from SessionException?
You need to perform all your database actions within a transaction scope. As you identified its usually considered good design to let the service layer of your database model deal with transactions. The only constraint then becomes that you must invoke your service model to get within the transaction scope, which might be undesirable during test.
I would recommend to make use of the testing fascilites provided by spring. See 9.3.2.3 Transaction management
You could also manually create a transaction before testing your method, e.g., by
Session sess = factory.openSession();
Transaction tx = null;
// try catch
tx = sess.beginTransaction();
findByUserId(userId);
tx.commit();
tx.rollBack();
Put the following annotations on the top of your test class.
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
#ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml")
Also I wouldn't worry about putting additional #Transactional in DAOs.
Spring usually checks to see if you are already in a transaction (with in the same thread) before it creates another.
"But as I understand, transaction
management should be the duty of
service tier to avoid unnecessary
transactions creation."
This is more of a design choice (Spring Roo for example violates this)
You can use this annotation on your controller method:
#Transactional(readOnly = true)

HibernateDaoSupport , transaction is not rolled back

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.

Categories

Resources