I am using hibernate and spring and I am getting this exception upon executing the following code:
Session oSession = getSession();
try
{
oSession.setFlushMode(FlushMode.COMMIT);
getHibernateTemplate().delete(oProject);
oSession.flush();
bResult = true;
}
catch (Exception e)
{
bResult = false;
logger.error(e);
}
I've read some session management regarding hibernate and I have a hunch that this code has poor session handling. What could be the reason of having two open sessions? Hibernate APIs says that the getSession() function returns either a new session object or an existing. In this case, where does it get the existing session object? and if it creates a new session object would that still be fine to process the collection involved?
Any help would be greatly appreciated. Thanks in advance! more power stackoverflow.
HibernateTemplate.delete(Object entity) will delete the object using other Session inside HibernateTemplate but you open a new Session object by your own, which is the root cause of the error. So you should try as following:
try
{
getHibernateTemplate().delete(oProject);
bResult = true;
}
catch (Exception e)
{
bResult = false;
logger.error(e);
}
Hibernate checks if there is a session already in opened for the current thread. If not, it creates a new one using the SessionFactory; otherwise it reuses the already opened session. Well you can reattach entity objects and the same goes for collections containing entity objects too.
But you have not mentioned how is Hibernate configured to handle sessions. It could be that you manually open sessions and the code you posted actually opens 2 sessions.
Related
I'm developing a JavaFX Hibernate desktop application. I configured my application so that I use the same session from the application runs till it close.
This is how I did it:
public static Session getCurrentSession() {
if (sessionFactory != null) {
Session session = sessionFactory.getCurrentSession();
if (session != null) {
return sessionFactory.getCurrentSession();
} else {
session = sessionFactory.openSession();
session.beginTransaction();
return session;
}
}
return null;
}
And when the User close the App, I run a second method that closes the session and the SessionFactory.
public static void closeConnections() {
if (sessionFactory != null) {
if (sessionFactory.getCurrentSession().isOpen()) {
sessionFactory.getCurrentSession().close();
}
sessionFactory.close();
}
}
I'm newB on Hibernate so be kind with me PEACE
Hibernate session should be thought of as a "single-unit-of-work". One or more transactions can live in a session. The best practice is in most cases session-per-request.Open a session in the beginning of handling a request, and close it in the end.
Hibernate's 1st level cache is mantained in the "Session" so that if you keep it around in the user session it will be hitting "cached" objects.
Hibernate has 2nd level cache that you have to configure (if you want) to take advantage of. The 2nd level basically supports the following: queries, objects with load and get, and collections/associations and provides cached objects across Sessions, SessionFactories, and Clusters.
You are not using one session per application, you are using the "current session" concept, which opens a session and stores it in a context.If you don't close your session it will stay there.
OK, for your basic question:
Is it a good practice to use the same Hibernate Session over and over?
Answer is no,the session objects should not be kept open for a long time because they are not usually thread safe and they should be created and destroyed them as needed.
What it is usually done in hibernate is:
You open a session (which is basically a database connection), do transactions, and then close your connection (close your session). In other words, you can check some other post's analogy :
What is the difference between a session and a transaction in JPA 2.0?
Hope it helps
How can I create payment in jBilling programmatically from scheduled plugin? The problem is I want to create a payment which is not linked to any invoice, so I try to use
applyPayment(PaymentDTOEx payment, Integer invoiceId, Integer executorUserId)
with invoiceId=null, but it leads to an error:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Initially I try:
IPaymentSessionBean psb = Context.getBean(Context.Name.PAYMENT_SESSION);
psb.applyPayment(new PaymentDTOEx(paymentWS), null, userID);
Later I added "userbl.webServicesAuthenticate(user, pass)" before, but result is the same.
I think I missed something important and maybe doing it completely wrong.
I've never used jBilling before, but after a bit of googling it seems like it uses Spring to manage transactions etc.
From the error you've quoted it looks like you don't have a Hibernate session open. If you were using a web framework (like Spring MVC, for example), the Hibernate session lifecycle is usually managed for you transparently using a servlet filter.
If you're executing a payment from a scheduled service, then you may need to open and close the Hibernate session yourself in your service. There's some documentation here that describes how to do this programmatically using Spring.
Also take a look at the #Transactional annotation. It might be as simple as annotating your scheduled job method with this.
Thanks to rcgeorge23!
The problem was there were no active Hibernate session opened. Here is working code:
IPaymentSessionBean psb = Context.getBean(Context.Name.PAYMENT_SESSION);
//transaction manager is available in jBilling like that:
PlatformTransactionManager txManager = Context.getBean(Context.Name.TRANSACTION_MANAGER);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("CreatePaymentTransaction");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //not sure which strategy is best in this case
TransactionStatus status = txManager.getTransaction(def);
String ret;
try {
ret =Integer.toString(psb.applyPayment(new PaymentDTOEx(paymentWS), null, userID));
}
catch (Exception ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
You can also create plug-in for user.
for example when user will created or added then the default amount should be paid.
for that you have to write a plug-in and it will occure when user will created.
I have a question about this Hibernate samples. I didn't found an answer in Hibernate docs or in Manning Persistence with JPA. May be someone can explain what happens when I use plain JDBC.
Session session = null;
Transaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
// Transaction actions
tx.commit();
}
catch (RuntimeException ex) {
try {
tx.rollback();
}
catch (RuntimeException rbEx) {
log.error("Couldn’t roll back transaction", rbEx);
}
throw ex;
}
finally {
session.close();
}
My question is what will happen if transaction rollback method throw an exception? Will some transaction data be stored in database? How can I handle this exception?
My question is what will happen if transaction rollback method throw an exception?
It depends on what the exception is.
Will some transaction data be stored in database?
Unspecified. One would hope that the database will be able to recover to a point corresponding to the start of the transaction. However, there are scenarios where even that may not be possible; e.g. if you lost a disc drive, and you don't have a hot standby.
How can I handle this exception?
In general, you can't. If you get an exception and have no idea what it means or what caused it, the only sensible thing you can do (in a typical database application) is to shut the application down and get a human being to investigate the problem.
I've got jsp webapp on my VPS host with tomcat 7 as server. I'm using Hibernate 3 and PostgreSQL. All methods in my class DBManager (responsible for db services, connection, queries) use almost the same structure:
Session session = sessionFactory.openSession();
session.beginTransaction();
=======
HERE HQL QUERY/session.get/update/save etc are executed
=======
session.getTransaction().commit();
session.close();
The problem is that my VPS after some time (using my webapp) shows many idle postgres processes which causes server overloading and e.x VPS kills Java or refuses connection to DB. What can I do to remove the problem? Is this a problem caused by my code or something else?
You need to place session.close() in try/finally block:
try {
session.beginTransaction();
=======
HERE HQL QUERY/session.get/update/save etc are executed
=======
session.getTransaction().commit();
} catch (SQLException sqle) {
// handle the exception, e.g. session.getTransaction().rollback();
} finally {
session.close(); // this will require another try/catch
}
If exception happens somewhere in your code, the session doesn't get closed and leaks resources.
Problem solved. What I did wrong was creating new factory in each instance of class. Now I added static reference everywhere and it is working pretty good.
I am using Hibernate in my app, and noticed that whenever a Hibernate error is thrown, the application eventually crashes with DB-related errors. From what I've read, the issue is that the Hibernate session is in some sort of unusable state, and therefore needs to be discarded. However, it is being returned to the pool and being re-used on the next call, instead of being discarded.
What is the correct way to ensure, at the start of each function, that the session is usable, and if not, to make sure it is discarded properly and a new session started?
My Hibernate config file includes the following:
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.timeout">60</property>
<property name="hibernate.c3p0.idle_test_period">45</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.preferredTestQuery">SELECT 1;</property>
<property name="hibernate.c3p0.testConnectionOnCheckout">true</property>
<property name="hibernate.c3p0.acquireRetryAttempts">3</property>
and my code that has this error (complete function calls) is:
public static ReturnCodes newUser(Long id, String username, String country) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
//check for duplicate user
User checkUser = getUserByExternalID(id, true);
if (checkUser != null && checkUser.getId().intValue() == id.intValue()) {
transaction.commit();
return ReturnCodes.DUPLICATE;
}
User newUser = new User();
newUser.setUsername(username);
newUser.setExternalID(id);
newUser.setCountry(country);
session.save(newUser);
transaction.commit();
return ReturnCodes.SUCCESS;
} catch (ConstraintViolationException e) {
log.info("The user must already exists, so cleanup and return DUPLICATE.");
return ReturnCodes.DUPLICATE;
} catch (Exception e) {
log.info("An unknown error occurred, so cleanup and return GENERAL FAILURE.");
return ReturnCodes.GENERAL_FAILURE;
}
}
public static User getUserByExternalID(Long userid, boolean leaveTransaction) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
User user = null;
try {
session.beginTransaction();
Criteria c = session.createCriteria(User.class);
c.add(Restrictions.eq("externalID", userid));
user = (User)c.uniqueResult();
if (!leaveTransaction)
session.getTransaction().commit();
} catch (Exception e) {
log.error("Could not retrieve user with External ID " + userid, e);
}
return user;
}
Session and transaction management is a bit complex.
Spring has implemented it, by annotating methods with #Transactional.
If you want to handle that manually, read this. You can use a Filter to start a session, or some proxy and a ThreadLocal. Most commonly a session is created per-request.
The most common approach is to manage your transactions and Hibernate sessions in the services, a layer above DAO. In that case you can perform several database operations in the same transaction. For example, in your case you can explicitly check whether user with the given username already exists before trying to create a new one. So, you can let Hibernate handle all SQLExceptions and to convert them to a runtime exception.
This is usually done by injecting transaction management code via a dependency injection library. The most popular DI library is Spring.
What I ended up doing is to add the following line to every catch block:
session.clear();
which, according to the documentation,
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.
The result of this is that the session is returned to a usable state, and future uses of the same session will not be impacted by the earlier error.
This does not, of course, solve any issues surrounding proper demarcation of transactional scope, which Olaf and Bozho correctly explain is best handled outside the scope of any particular DAO.