Reputation: 309
I'm writing a JSF 2.0 application with Hibernate and Postgresql database. My problem is quite poor understanding on how to handle session with Hibernate when inserting data into more than one table at a time. I have a method savePerson. The method is called as many times as there are addresses submitted by a user but the object Person is only created once. The method savePerson then calls the method addAddress. The code looks like this:
public Person savePerson(Person p, String address) {
Transaction tx = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
if (p == null) {
= new Person();
try {
tx = session.beginTransaction();
session.save(p);
tx.commit();
} catch (RuntimeException e) {
if (tx != null && tx.isActive()) {
try {
tx.rollback();
} catch (HibernateException e1) {
}
throw e;
}
}
}
int id = p.getId();
addAddress(4, id, address);
return p;
}
And the method addAddress:
public void addAddress(int table_id, int row_id, String address) {
Transaction tx = null;
session = HibernateUtil.getSessionFactory().openSession();
Address a = new Address(table_id, row_id, address);
try {
tx = session.beginTransaction();
session.save(a);
tx.commit();
} catch (RuntimeException e) {
System.out.println("first try");
if (tx != null && tx.isActive()) {
System.out.println("first try if");
try {
System.out.println("first try if try");
tx.rollback();
} catch (HibernateException e1) {
}
// throw again the first exception
throw e;
}
throw e;
}
But I get the following error:
org.hibernate.TransactionException: Transaction not successfully started
So what is the proper way of opening and closing session when inserting the data into more than one table at a time?
Best Regards, sass.
Upvotes: 1
Views: 1103
Reputation: 570595
A TransactionException
indicates that a transaction could not be begun, committed or rolled back. But providing the full stacktrace would probably helpful to fully understand the problem.
That being said, while you can create multiple (serial) Transaction
from a single Session
, there is IMO a major flaw in your design. If you need to insert both the Person
and the Address
, you should very likely do it in a single unit of work. With your current approach, adding an Address
can fail and leave a freshly inserted Person
in an inconsistent state.
So what is the proper way of opening and closing session when inserting the data into more than one table at a time?
Do it in a single transaction.
And if you want to remove the transaction management from your methods, you should consider using the Open Session In View pattern, as suggested by BalusC. Unless you want finer grained transaction control of course.
Upvotes: 1
Reputation: 1109570
A common practice would be to create a Filter
which opens the Hibernate session before processing the request/response and commits and closes the session after processing the request/response. Finally map this Filter
on <servlet-name>
of FacesServlet
. This is called Open Session In View or Open Session Per Request.
Spring provides such a filter out of the box, the OpenSessionInViewFilter
, which is useful for the case that you're already using Spring or are considering to use it. If you don't (want to) do Spring, you can find here another concrete kickoff examples which you could just copypaste and finetune/expand.
Another practices are listed in this MyFaces FAQ (although MyFaces 1.2 targeted, this applies as good on Mojarra 1.x and 2.x).
Upvotes: 1