hibernate session.save() does not reflect in database - java

According to my understanding in hibernate (please confirm)
1- You have to session.close() if you get it by getSessionFactory().openSession().
2- No need to session.close() if you get it by getSessionFactory().getCurrentSession(). It is automatically closed after commit().
3- #2 When using getSessionFactory().getCurrentSession(), we have to do all DB activities inside an active transaction so that we can commit() at the end.
4- Hibernate en-queues all save, update, and delete operations and submits them to the database server only after a flush() operation or committing the transaction or closing of the session in which these operations occur.(as per javadoc)
From the above points if I consider 1 & 4, then the following code should work:
Session session = HibernateUtil.getSessionFactory().openSession();
AccountDetails ac = new AccountDetails();
//perform set operations
session.save(ac);
session.close();
System.out.println("new account stored.");
BUT it is not working i.e. it runs smoothly but does not reflect(store) in database.Why this is so ? When I write the code inside a transaction and commit, then it is stored.
I think I am missing a basic thing. Please clarify.

When you create session using SessionFactory.openSession(), no transaction is created, so your operations are executed outside of transaction context. In order to see your changes, you have to start a new transaction, or perform your operations as a part of ongoing transaction. From documentation:
A typical transaction should use the following idiom:
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
//do some work
...
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}

I was also trying to understand the point: save() can perform Insert operation outside transaction boundary so I did something like this
SessionFactory factory = new Configuration().configure()
.buildSessionFactory();
Session session = factory.openSession();
session.save(user);
session.close();
But data not inserted in database.So I again tried this and now it worked for me and data inserted sucessfully:
in configuration file:
<property name="connection.autocommit">true</property>
and in java code:
SessionFactory factory = new Configuration().configure()
.buildSessionFactory();
Session session = factory.openSession();
session.save(user);
session.flush();
session.close();

Yeah session.save is not saved to database without have the transaction.
Only way to do it is by using the
<property name="connection.autocommit">true</property>
If this property is used you no need transaction and also you do not need session.flush() or session.close()

session.close() is only responsible to close the session
https://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/Session.html#close()
how to work with hibernate session:
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/transactions.html#transactions-basics
// Non-managed environment idiom
Session sess = factory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
// do some work
...
tx.commit();
}
catch (RuntimeException e) {
if (tx != null) tx.rollback();
throw e; // or display error message
}
finally {
sess.close();
}
As it wrote in the documentation:
a much more flexible solution is Hibernate's built-in "current session" context management:
// Non-managed environment idiom with getCurrentSession()
try {
factory.getCurrentSession().beginTransaction();
// do some work
...
factory.getCurrentSession().getTransaction().commit();
}
catch (RuntimeException e) {
factory.getCurrentSession().getTransaction().rollback();
throw e; // or display error message
}

Whenever you carry out any unit of work on the database objects, Transactions have to be used. http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/transactions.html shows why they are used and how they can be used. But, the key is to use a transaction object by calling session.beginTransaction() which returns a Transaction object. This will represent the unit of work carried out to the database.

I found I had to flush and then refresh the DAO, and then it worked.
session.flush()
session.refresh(entityDAO)

You forgot to commit .You should to commit.
session.save(ac);
// you should to add this bottom line
session.getTransaction().commit();

Whenever Your are doing save(), Always commit the transaction once done.
Account ac =new account()
ac.insert(123);
----------
----------
----------
----------
session.save(ac);
// Add this bottom line
session.getTransaction().commit();

if there is DB manipulation operation then it should be in transaction
if you call session.save(object)
hibernate create bellow query only .
select hibernate_sequence.nextval from dual
so right code is here
Transaction t=session.beginTransaction();
session.save(obect);
t.commit(); should not forgot to commit.
session.close();

Related

Hibernate transaction throws exception from another transaction

I'm trying to save data using Hibernate. Everything happens within the same session. The logic is following :
1) Begin a transaction and try to save :
try
{
session.getTransaction().begin();
session.save(result);
session.getTransaction().commit();
}
catch (Exception e)
{
session.getTransaction().rollback();
throw e;
}
2) If a new record violates integrity constraint catch an exception in the outer wrapper method, open another transaction and query more data
catch (ConstraintViolationException e)
{
if ("23000".equals(e.getSQLException().getSQLState()))
{
...
session.getTransaction().begin();
Query query = session.createQuery("from Appointment a where a.begin >= :begin and a.end <= :end");
query.setDate("begin", date);
query.setDate("end", DateUtils.addDays(date, 1));
List results = query.list();
session.getTransaction().commit();
The problem is when the second transaction performs query.list it throws an exception that should'be been linked with the previous transaction.
SQLIntegrityConstraintViolationException: ORA-00001: unique constraint
Should I query data from another session or what's the other way to isolate two transactions from each other?
Thanks!
You should not use the same session if you get an exception, you have to close the session and use a different session for your second operation. This is given in hibernate documentation:
13.2.3 Exception Handling
If the Session throws an exception, including any SQLException,
immediately rollback the database transaction, call Session.close()
and discard the Session instance. Certain methods of Session will not
leave the session in a consistent state. No exception thrown by
Hibernate can be treated as recoverable. Ensure that the Session will
be closed by calling close() in a finally block.
Hope the Exception class is base for all types of exceptions, hence if it is placed before it will be catched always and rest of the exception handling is isolated.
Can you try to replce session.save() with session.persist method, hope this might resolve your problem. Refer following link for more details about both methods.
What's the advantage of persist() vs save() in Hibernate?

Hibernate JPA constraint violation and Transaction already active

I have a table with the field 'nom' with the unique constraint and when I test to insert a value of this field that already exists in the table the org.hibernate.exception.ConstraintViolationException is thrown. Then after all my persisting I get a Transaction already active Exception.
this is my persisting method in a Dao class
public void persist(E entity) throws Exception {
EntityTransaction tr=entityManager.getTransaction() ;
tr.begin();
entityManager.persist(entity);
tr.commit();
}
and here the code where I catch the exception
try {
rd.persist(r);
} catch (Exception e) {
e.printStackTrace();
}
How Can I solve this Transaction problem ?
Instead of explicitly opening the transaction you could allow the framework to handle the transaction (like in spring you can use the #transactional). But if not it looks like the code has a begin and a commit in case it is successful, try adding a tr.rollback() in the persist method using a finally (or you could even check whether the transaction is still active using the tr.isActive() method.
There is no need to do anything with Transaction, because it is handled by Spring.
I met "Transaction already active". Though I think what caused it is different with your problem, I think my answer should help someone.
For example:
// Transaction handled by Spring
Session session = sessionFactory.getCurrentSession();
...
return;
------------------------------------------------------------
// Transaction handled by yourself
Session session = sessionFactory.openSession();
Transcation tr = session.beginTransaction();
...
tr.commit();
session.close();
return;

hibernate multiple threads prevent multiple save(), JTA necessary?

I'm using a hibernate session per request model for my web application. My jdbc transaction begins at the beginning of each web request and commited at the end.
// Non-managed environment idiom
Session sess = factory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
// do some work
...
tx.commit();
}
catch (RuntimeException e) {
if (tx != null) tx.rollback();
throw e; // or display error message
}
finally {
sess.close();
}
I'm faced with the problem where I am testing for existence of an entity (A) based on several parameters and doing an insert only if it doesn't exist.
public synchronized myMethod(param1, param2) {
MyEntityA entity = MyEntityADAO.findEntity(param1, param2)
if (entity == null) {
entity = .../create entity
MyEntityADAO.save(entity);
}
}
the problem is that synchronization does not help because the call to MyEntityADAO.save() does not actually write to the database when the currently running thread exits the method and releases the lock, the write to the database occurs after the transaction is commited which is generally what I need for my application except for a few scenarios. The code above causes multiple records saved with same parameters in a multithreaded environment.
I've tried to execute the save code in its own new session and transaction:
public synchronized myMethod(param1, param2) {
MyEntityA entity = MyEntityADAO.findEntity(param1, param2)
if (entity == null) {
entity = .../create entity
Session session = HibernateUtil.createSession();
MyEntityADAO.save(entity);
Transaction t = session.beginTransaction();
}
}
the above causes problems with 2 open sessions loading the same collection with hibernate in some instances.
Should I enclose every DAO call in its own transaction and use transaction propagation with JTA? Is there a way to avoid JTA? Is it alright to commit transaction associated with the main session after the call to MyEntityADAO.save() and call beginTransaction on the main session right after and have the transaction commited at the end of the request as it does now?
The coherence of the data in database should not be compromised by doing only some part of an atomic change in its own transaction. And although some synchronization might work on your environment, if you need to cluster your app, or if several applications acces the database, it won't solve the problem.
What you should do is to put a unique constraint in the database on [param1 - param2]. That will cause one of the two transactions to rollback if there is a race condition.
If you choose to still isolate the check/insert code in its own transaction (because it's not a problem if that succeeds and the outer transaction fails), I don't see how JTA would be a problem. Supposing you're using EJBs or Spring, just put this method in its own EJB/bean, and mark the method as transactional, with the REQUIRES_NEW propagation.
The code would thus look like this:
// some code
Long id = myBean.checkIfExistOrCreate(param1, param2); // this methos call starts a new transaction
// now we're sure that the entity exists. Load it in the current session.
MyEntity e = em.find(MyEntity.class, id);
If you can't synchronize checkIfExistOrCreate, then try calling it, catch any exception that it could throw, and retry calling it:
Long id = null;
try {
id = myBean.checkIfExistOrCreate(param1, param2);
}
catch (Exception e) { // a well-defined exception would be better
// the transaction roled back: retry
id = myBean.checkIfExistOrCreate(param1, param2);
}
// now we're sure that the entity exists. Load it in the current session.
MyEntity e = em.find(MyEntity.class, id);
The solution that worked for me and my particular app requirements trying to avoid JTA and nested transactions:
Using ManagedSessionContext because org.hibernate.context.ThreadLocalSessionContext will close and create a new session for each transaction. You will run into problems with entities that have collections associated if you load those entities in multiple open sessions (when you will create multiple transactions for one request).
I open a hibernate session and bind it to the context in the beginning of my web request
Any service layer method that needs test for existence prior to insert is marked synchronized, the global transaction is commited with the insert statement and a new transaction is started
At the end the request the transaction bound to the session is commited
public synchronized myMethod(param1, param2) {
MyEntityA entity = MyEntityADAO.findEntity(param1, param2)
if (entity == null) {
entity = .../create entity
MyEntityADAO.save(entity);
HibernateUtil.getCurrentSession().getTransaction().commit();
HibernateUtil.getCurrentSession().getTransaction().begin();
}
}
I know its ugly and will not work for everybody in every scenerio, but after doing a very intense search on transaction management, isolation levels, locking, versioning that is the only solution I have found that worked for me. I am not using Spring, and I'm not using a Java EE container, using Tomcat 6.

Hibernate code..some confusion

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
Consultants consultants = new Consultants(); // 1
consultants.setUsername("Rahul"); // 2
consultants.setPass("rahul"); // 3
session.save(consultants);
transaction.commit();
} catch (HibernateException e) {
System.out.println("Exception:"+e.getMessage());
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
see, in above code except 1,2 and 3 statement all code remains same for each method. Is there any best way to re-write above code each time i.e way to us same code again and again?
Thank you!
Not sure about what kind of repetition are you complaining about, but you can create a "generic" method to save any mapped entity:
public void save(Object entity) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
session.save(entity);
transaction.commit();
} catch (HibernateException e) {
System.out.println("Exception:"+e.getMessage());
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
And then use this method when you want to save a Consultant:
Consultants consultants = new Consultants();
consultants.setUsername("Rahul");
consultants.setPass("rahul");
save(consultants);
Kind Regards,
Yes, very definitely. What you've identified is an opportunity for applying the template method pattern. See, for example, Spring's TransactionTemplate. Even if you don't want to use Spring--if you're using Hibernate, you should probably manage it with Spring anyway--you can take a look at the source to see how it can be done.
By mean all code you mean the transaction handling and the roll back mechanism?
I real word application generally Transaction are being regarded as another layer and we generally call this as separation of concern.
If you are using Spring, all you have to do is to move your transaction handling outside of the java code using AOP.
Without Spring there are other way to handle transaction management
here is the link to spring documentation for transaction management
transaction management
transaction = session.beginTransaction();
session.save(entity);
transaction.commit();
To avoid the above repetition in all persistence related method you have to go through HibernateTemplate or JpaTemplate Which handle the above repetition for us. And for save operation you have to just call save(object) it will save your data into the persistence you don't have to worry about the implementation of it.

How JPA (Hibernate) deal with transaction when fetching Object from database

I'm currently developping an application in java using Hibernate as a persistence manager and JPA as an abstraction of the persistence manage hibernate.
I'd like to know the impact of wrapping a result query around a transaction. I know the entity manager must stay open for lazily fetched field bug what about transaction in all this ?
Here is a code example with transaction activation/desactivation ability.
public List<Exportdata> get(Integer max, EntityManager em, Boolean withTransaction) {
EntityTransaction tx = null;
try {
if (withTransaction) {
tx = em.getTransaction();
tx.begin();
}
Query query = em.createQuery("from Exportdata");
query.setMaxResults(10);
List<Exportdata> list = query.getResultList();
if (withTransaction)
tx.commit();
return list;
} catch (RuntimeException re) {
if (withTransaction)
if (tx != null && tx.isActive())
tx.rollback();
throw re;
}
}
What is the difference between enabling or disabling withTransaction when this function is called ?
Thanks all,
Fred
There is no practical difference here, since you aren't changing any data. The query you execute will generate an SQL select. Transactions are there to allow you to apply ACID properties to a collection of inserts, updates, etc.
However, if you begin manipulating the objects in the list returned from this method, calling setters, etc. those changes will be propagated back to the database out-with a transaction on an ad-hoc basis. In other words you'll effectively be working with the db in auto-commit mode. This is unlikely to be what you want.
The important thing to understand is that the duration of a persistence context and a transaction can be managed separately. Often though you would want to manage them together.

Categories

Resources