I would like to flush all the entites stored in the current transaction to the database (without ending the current transaction via commit).
Do I need to check if the transaction is Active before doing so?
if (this.entityTransaction.isActive())
{
this.entityManager.flush();
}
Thank you
According to the javadoc of the method flush of eclipselink's EntityManager class:
https://www.eclipse.org/eclipselink/api/2.6/javax/persistence/EntityManager.html#flush()
void flush()
Synchronize the persistence context to the underlying database.
Throws:
TransactionRequiredException - if there is no transaction or if the entity manager has not been joined to the current transaction
PersistenceException - if the flush fails
So yes it looks like you need to check, other ways you might get an exception of type "TransactionRequiredException"
Related
I'm currently having problem with executing transaction inside stateless session.
On a service layer i have defined transaction using #Transactional annotation (which is required because the methods needs to be in one transaction).
Inside the method I create new entity Car.
However I also have to create in underlaying methods custom transtaction inside stateless session (its done for performance) like this
StatelessSession session = getSessionFactory().openStatelessSession();
Transaction transaction = session.beginTransaction()
// create and setup CarRequirements entity
transaction.commit;
Problem is that the entity CarRequirements has foreign key to entity Car. Therefore when i try to commit the underlaying transaction an exception occurs because obviously the Car entity is not yet commited to database.
Is there a way to postpone the commit of underlaying transaction or force commit of the Car entity?
either you define a relationship between CarRequirements and Car (cascade)
or you have to save a Car firstly then save CareRequirements
I am working an a JPA 2.0 project, where I am saving my Entity class objects like :-
InitialContext ctx = new InitialContext();
UserTransaction userTrans = (UserTransaction)
ctx.lookup("java:comp/UserTransaction");
EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_NAME);
EntityManager em = emf.createEntityManager();
User user = new User("ankit","nigam",25);
em.persist(user); // persisted in db after this executes
userTrans.commit(); // whether it is required OR not.
So whether I am using userTrans.commit() or not, my user object is getting saved in Db, after persist() executes. But some of my colleagues say, as a standard we should commit() the transaction.
What should be the approach which I follow and whats the logic behind commit() and persist(). Please throw some lights.
Is autocommit ON in your DB? If it is then that is the reason why the changes get permanently stored in your DB irrespective of whether or not you commit the transaction from your application. In production the autocommit is generally set OFF because it hampers the performance/response time of the DB, that is why developers are generally encouraged to control the commit or rollback of a transaction from their application. The link details the command to handle autocommit in db2: http://www.db2util.com/administration/options-db2-command-line-disable-autocommit/
I'm using Hibernate transaction for read operation from db as following excample code:
Session session = sessionFactory.openSession();
Transaction tx= session.beginTransaction();
session.get(Account.class, new Long(id));
tx.commit(); //Actually I use tx.rollback()
session.close();
Due to the second level cache, result is fetched from cache after the first time reading from db. But the database connection is distributed when session.beginTransaction() is invoked, and next commit statement will be executed at database, which degrades the performance dramatically(compared to the case when no transaction is used).
So is there any possible way to know that the result will be read from second level cache so I can avoid doing commit and even use a new database connection?
Assuming you are using spring transaction support, have your tried using SUPPORTS propagation level?
#Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
I have the following piece of code:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("test")
EntityManager entityManager = emf.createEntityManager()
User user = entityManager.find(User.class, 0);
entityManager.getTransaction().begin();
entityManager.getTransaction().rollback();
entityManager.refresh(user);
This throws an IllegalArgumentException on the fourth line saying "Entity not managed". If I change the third line to .commit() instead of .rollback(), everything seems to work fine.
What is going on here? Can I prevent this from happening?
UPDATE: #DataNucleus is directing me towards PersistenceContext. How do I change the persistence context in my code?
From the JSR-000317 Persistence Specification for Eval 2.0 Eval:
3.3.2 Transaction Rollback
For both transaction-scoped and extended persistence contexts, transaction rollback causes all pre-existing managed instances and removed instances
[31]
to become detached. The instances’ state will be the
state of the instances at the point at which the transaction was rolled back. Transaction rollback typically
causes the persistence context to be in an inconsistent state at the point of rollback. In particular, the
state of version attributes and generated state (e.g., generated primary keys) may be inconsistent.
Instances that were formerly managed by the persistence context (including new instances that were
made persistent in that transaction) may therefore not be reusable in the same manner as other detached
objects—for example, they may fail when passed to the merge operation.
[32]
In a PersistenceContext of "Transaction" then commit/rollback will detach objects used in the transaction. In PersistenceContext of "Extended" then commit/rollback do nothing like that, and objects are detached at close of the EM. Depends on your context
I am currently working with #PostPersist and #PostUpdate, and in those triggers I am persisting additional entities. The question is, are those triggers in the same transaction and if not is it possible to force it ?
For me it works this way.
While I was looking through the logs the transaction isn't existing ( it's commited just before the trigger is launched ) which prevents me ( without REQUIRES_NEW on the persisting method from injected bean ) from saving the additional entities in database.
REQUIRED attribute is totally ignored, and MANDATORY attribute do not throw an exception.
Can it be the problem with JUnit ( since I am in the dev. phase and did not test the behavior on full env. ) ?
If extending the transaction on this triggers is not possible, how to ensure that if the rollback occurs before the #PostPersist and #PostUpdate, those operations also will be rollbacked.
If you're using Spring you could always register a TransactionSynchronization with your current transaction manager to be called back on events such as commits of your currently running transaction:
#PostPersist
void onPersist() {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
#Override
public void beforeCommit(boolean readOnly) {
// do work
}
});
}
}
A TransactionSynchronization also provides callbacks after a transaction has committed successfully and before/after a transaction completes.
If you need to inspect if the transaction was committed or rolled back, use afterCompletion(int status).
For details have a look at TransactionSynchronization's JavaDoc.
The firing of a PostPersist event does not indicate that the entity has done a successful commit. The transaction may be rolled back after the firing of the event but before the successful commit.
If you in the PostPersist get the entity manager used in the transaction and then do somehting like this:
#PostPersist
void someMethod() {
EntityManager em = null;
em = getEntityManagerUsedInTransaction();
EntityTransaction et = em.getTransaction(); // should return the current transaction
if (et.isActive() ) {
// do more db stuff
}
}
NB: I haven't tried this so it's only speculation (tho' I have used the lifetime event trigger extensively for other stuff).
I have to add that I don't think this is a good idea. Use the PostPersist to flag that other entities should be persisted and do it in another transaction.