Is the below statement a valid one?
persist() also guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries
When I try the below code using persist; then the row is getting inserted without any transaction (It is commented out).
SessionFactory sessionFactory = new Configuration().configure("student.cfg.xml").buildSessionFactory();
Session session = sessionFactory.openSession();
//Transaction tran = session.beginTransaction();
/*
* Persist is working without transaction boundaries ===> why?
*/
Student student = new Student();
student.setFirstName("xxx");
student.setLastName("yyy");
student.setCity("zzz");
student.setState("ppp");
student.setCountry("###");
student.setId("123456");
session.persist(student);
//tran.commit();
session.flush();
session.close();
persist() also guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries
This statement is correct. When control returns from persist() back to your code, no INSERT statements have been executed. These statements are guaranteed to be deferred until session flushing. Note that persist() would be a pointless method if no insert happened ever.
AFAIK data is saving because of session.flush(), try after removing this, mostly you will get an error.
Hibernate persist
Diff. save & persist
Related
In hibernate, session.save() is supposed to save the records.It generates "insert" queries. However, I have written below simple program to check this. I am observing the save() can also be used to update the records. It is generating "update" query. Isn't save() doing the same job as saveorupdate() in the below program ?
SessionFactory sf = conf.buildSessionFactory();
Session session = sf.openSession();
Transaction trans = session.beginTransaction();
Vehicle veh = new Vehicle();
veh.setId(1);
veh.setModel("Veh_mod");
veh.setName("Veh_Name");
Serializable obj = session.save(veh);
veh.setModel("Veh_mod_change");
obj = session.save(veh);
session.flush();
trans.commit();
session.close();
------------------------- in the console--------------------------------
Hibernate:
/* insert com.anvesh.test.Vehicle
*/ insert
into
VEHICLE
(NAME, MODEL, ID)
values
(?, ?, ?)
Hibernate:
/* update
com.anvesh.test.Vehicle */ update
VEHICLE
set
NAME=?,
MODEL=?
where
ID=?
After your first call to save(), object veh becomes an attached object (aka. persistent object state). Subsequently mutating that object with setModel() and committing the transaction would cause hibernate to fire an update even without calling save() a second time.
Here's an example for reference: http://www.dineshonjava.com/p/transient-persistent-and-detached.html#.VEfGCme8G7E
Or perhaps a short video tutorial: http://javabrains.koushik.org/tutorials/hibernate_run/Hibernate-Tutorial-22---Transient,-Persistent-and-Detached-Objects.html
save() can do an update, if id is set on the object it saves. Check out this thread for differences between various saving methods. To quote from an accepted answer
save Persists an entity. Will assign an identifier if one doesn't exist. If one does, it's essentially doing an update. Returns the generated ID of the entity.
When you first called session.save(veh), your object becomes associated with the session.
Hibernate will then know that it needs to use an "UPDATE" query when you save the object again.
Try:
Vehicle veh1 = new Vehicle();
veh1.setId(1);
veh1.setModel("Veh_mod");
veh1.setName("Veh_Name");
Vehicle veh2 = new Vehicle();
veh2.setId(1);
veh2.setModel("Veh_mod");
veh2.setName("Veh_Name");
session1.save(veh1);
session2.save(veh2); // try changing this to session2.saveOrUpdate()
then you'll see the difference between session.save() and session.saveOrUpdate()
As per Session.setFlushMode(FlushMode) we can set FlushMode to the session. Now I am trying to test how the Flushmode.COMMIT mode works with a small example.
I have created an entity called Cat with just 2 properties id and name. Now here is the code that I am testing:
Session session = getSession();
session.setFlushMode(FlushMode.COMMIT);
Transaction tx = session.beginTransaction();
Cat cat = (Cat) session.get(Cat.class, 1);
cat.setName(name);
session.flush();
//tx.commit();
session.close();
From logs I can see that when the line session.flush() is executed then hibernate is issuing JDBC update call to database as:
Hibernate: update Cat set name=? where id=?
As I set the FlushMode to COMMIT, I am expecting that the update query will be executed only when I say tx.commit() but the flushing is happening at session.flush(). Can someone please explain why it is happening like this?
Note the Javadoc of Session#flush().
Force this session to flush. Must be called at the end of a unit of
work, before committing the transaction and closing the session
(depending on flush-mode, Transaction.commit() calls this method).
or the javadoc for FlushMode#MANUAL
The Session is only ever flushed when Session.flush() is explicitly
called by the application. This mode is very efficient for read only
transactions.
Setting a FlushMode simply defines when flush() will happen automatically (all but MANUAL). If you call flush() yourself, manually, you're overriding that behavior.
I have a web service method that uses EclipseLink JPA. This method basically inserts data into the database. Something like :
public void insert(parameters....)
{
em.getTransaction().begin();
em.persist(employee);
em.getTransaction().commit();
// em.close();
}
Now at the client end, i have a loop that performs inserts per iteration :
for(......)
{
websrvice.insert(parameters...)
}
After the first iteration, i get a "No transaction is currently active" exception.
Then i thought of putting a Thread.sleep(2000) after each iteration which solves the problem.
So intuitively, this could be because another transaction is trying to commit before the latter is completed which causes the error. But then again i think, why would the second insert even start when the first isn't completed ? confused.
You shouldnt close the entity manager at the end of your transaction.
Remove this line:
em.close();
http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#close()
"Close an application-managed entity manager. After the close method has been invoked, all methods on theEntityManager instance and anyQuery and TypedQuery objects obtained from it will throw the IllegalStateException except forgetProperties, getTransaction,and isOpen (which will return false)"
Edit:
Try using the transaction returned by the first getTransaction call, rather than invoking this method twice:
EntityTransaction transaction = em.getTransaction();
transaction.begin();
em.persist(employee);
transaction.commit();
I read this in doc:
persist() also guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries.
But when I try this code:
SessionFactory sessionFactory = new Configuration().configure("student.cfg.xml").buildSessionFactory();
Session session = sessionFactory.openSession();
Student student = new Student();
student.setFirstName("XXX");
student.setLastName("YYY");
student.setCity("ZZZ");
student.setState("PPP");
student.setCountry("XXX");
student.setId("NNN");
session.persist(student);
session.flush();
session.close();
The record is getting inserted. As you can see in the above code, I have not used any transaction. Then in that case according to the doc, the data should not be inserted in the DB right?
Transaction boundaries means any operation between Transaction tran = session.beginTransaction(); and tran.commit(); right?
Please let me know where am I making the mistake.
Regards,
If you remove session.flush() and session.close(), you'll observe that no insert statement was executed. The point of that guarantee is that the persist call itself won't execute any statements; it doesn't say anything about the implication on the behavior of flush and close. Indeed, flush flushes all persistent objects to the datastore.
This is old magic!
if (getTransactionIsolation()==Connection.TRANSACTION_NONE
|| getAutoCommit()==true)
The persist() ignores the transaction boundary!
Why? persist() does not know about support transactions or not. In second case its committed because he didnt expected to need a transaction.
I'm trying to reattach to the session an object from the HTTP session that was originally retrieved from the DB, I do this by calling session.lock(object, LockMode.None) and even though lock does not cascade this works all right for me because it does not push updates to the DB like merge does (the lock is required to open a detail view in a pop-up and the actual saving would occur later on the main window). Now to my surprise I have found that if my entity has a one to many relation any changes on that collection would cause a HibernateException "Reassociated object has dirty collection".
How am I supposed to reattach objects to the session without updating the DB or discarding the changes on the object then?
Here is the situation as code
EntityA t = createAnEntityA();
Session sess = factory.openSession();
sess.beginTransaction();
sess.save(t);
sess.getTransaction().commit();
sess.close();
// t is now saved on the DB but in dettached state
// change a simple property
sess = factory.openSession();
sess.beginTransaction();
t.setPropertyB("B");
sess.lock(t, LockMode.NONE);
// t is attached again, you won't get LazyInitializationException
// by calling its properties, although you have to be careful
// because the reattachment does not cascade to children
sess.getTransaction().commit();
sess.close();
// no updates went to the DB because setPropertyB was called
// when t was still dettached
// now change a collection
EntityC c = createAnEntityC();
t.getCollectionPropertyC().add(c);
sess = factory.openSession();
sess.beginTransaction();
sess.lock(t, LockMode.NONE);
// Exception is thrown :-(
sess.getTransaction().commit();
sess.close();
I'm afraid currently it's not possible without hitting DB.
Apparently, the exception is happening because of lock command.
There's a Jira reporting this behavior.
https://hibernate.atlassian.net/browse/HHH-511
It has 2 patches to fix the problem. You could try those patches.
But if you problem is only Lazy loading of collection, you could consider using Open Session In View pattern. (maybe not the best pattern, but it can work for your case)