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;
Related
I am getting an error after removing object from database.
Error is:
java.lang.IllegalStateException: Transaction not active
org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:70)
I have simple app. I have EntityManagerFactory created on start up.
Every time if I want to work with database I create EntityManager and after work I close it like this:
Start up:
EntityManagerFactory emf = ....;
.
.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
try {
em.persist(OBJECT TO SAVE); //REALLY NEW OBJECT
} catch (Exception e) {
em.getTransaction().rollback();
}
em.getTransaction().commit();
em.close();
So, it's ok, I can save some object to db.
BUT If I want to remove item, I am getting an exception java.lang.IllegalStateException: Transaction not active.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
try {
em.remove(OBJECT TO REMOVE); //REALLY EXIST IN DB
} catch (Exception e) {
em.getTransaction().rollback();
}
em.getTransaction().commit();
em.close();
Can you help me with this? I don't know what it is....
EDIT: I found some code on google and I tried it:
em.getTransaction().begin();
em.remove(em.merge(OBJECT TO REMOVE));
em.getTransaction().commit();
And it worked for me!
Per Javadocs, entityManager.remove only works with Managed entities and if called on detached entities it will result in IllegalStateException.
So in your case your are calling em.remove on a detaced object and it is resulting in IllegalStateException and your catch block is catching it but your are not printing it. You may want to print the stacktrace in the catch block and this should show the IllegalStateException.
And finally after catching the exception you are still proceeding with commit on an rollbacked transacation and this is resulting in the exception you are seeing.
And the reason why em.remove(em.merge(object)) is working should be clear now. em.merge results in fetching the object from the database and so it becomes a managed entity and calling a remove method on managed entity results in successfully deleting it.
You can try using a Repository using save and remove methods for your transactions. It is a safer way.
#ApplicationScoped
#Repository
public abstract class MyEntityRepository implements EntityRepository<MyEntity, Long>, EntityManagerDelegate<MyEntity> {
}
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?
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();
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.
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.