The EntityManger is injected with #PersistenceContext annotation. This is a method from my "DAO/Repository" class which is not annotated. This class is injected into the EJB's that needs to get data from/to the database.
Until now I thought that after the persist method below is finished the persistencecontext is flushed and the data is stored to the database but from what happening in my app I start to doubt that. I have made the datasource and connection pool in Glassfish so I am using container managed transactions as far I know, however I do not use any transaction annotations.
Could somebody throw some light over it for me?
public void persist(QuestionFeedback questionFeedback) {
questionFeedback.setCreated(new Date());
entityManager.persist(questionFeedback);
}
Using Glassfish 3, Java EE6 compatiblity
The persist method makes the entity persistent, but doesn't yet write the change to the database. This normally happens when the transaction commits (the provider is free to optimize this, it could happen earlier).
With flush you can force the write to happen earlier, but it will still be visible only to code that participates in the current transaction. To make the write permanent (visible to all external code), the transaction still needs to be committed.
Without any explicit annotations, your EJB bean will be transactional by default.
Because EntityManager is injected via #PersistenceContext annotation, you are for sure using container managed transactions.
Anyway, your assumption that persist causes transaction commit is wrong. Change performed via persist is made to the database in commit. Documentation of EntityManager says that "new instance becomes both managed and persistent by invoking persist". In this context "becomes persist" does not mean entity is persisted to the database on that moment. On the moment when persist is called, entity is persisted in the terms of PersistenceContext. It is then later on persisted to the database latest when transaction commits.
Because you are not using any #TransactionAttribute annotations for your methods, default will apply. Default is TransactionAttributeType.REQUIRED. This will cause container to create transaction when first business method is called and propagate this on to other methods. Your transaction will commit when the call to the first business method is completed. Then your changes are in database (if no rollback was performed).
If you don't use any transaction annotations the default will be transactions being required. Thus your DAO will run in a transaction and the persistence context will no later be flushed than when the transaction is committed.
From the JavaDoc on TransactionAttribute:
If the TransactionAttribute annotation is not specified, and the bean uses container managed transaction demarcation, the semantics of the REQUIRED transaction attribute are assumed.
From the JavaDoc on FlushModeType:
When queries are executed within a transaction, if FlushModeType.AUTO is set on the Query or TypedQuery object, or if the flush mode setting for the persistence context is AUTO (the default) and a flush mode setting has not been specified for the Query or TypedQuery object, the persistence provider is responsible for ensuring that all updates to the state of all entities in the persistence context which could potentially affect the result of the query are visible to the processing of the query.
This means that the persistence context might be flushed earlier, if you use a query whose result might be influenced by that flush.
Related
I have a stateless EBJ and I am using JPA to manage database interactions. Below is my scenario where I need your help.
EJB received the call to fetch data (getCustomer()).
GetCustomer is used to read Customer entity from database using JPA.
The customer entity is having a method to remove spaces from attributes. which is annotated with #PostLoad. Basically this modifies the entity within persistence context.
Now when response is sent to client (after transaction completed ), its fires an update SQL to database to update the dataset (modified in step-3).
If you can see this operation, its a read-only in nature. But as my data is having lot many spaces, hence I have to trim it within entity object. But this approach is firing an update SQL which is not expected.
Could you please let me know the best approach to fix this issue or how to isolate and synchronize) EJB tx and JPA tx.
You can declare your getCustomer() to not support transactions:
#TransactionAttribute(NOT_SUPPORTED)
public Customer getCustomer()
Read more about transactions in the Java EE tutorial:
https://docs.oracle.com/javaee/7/tutorial/transactions003.htm
It is not necessary to mess with transaction management to achieve your requirement.
Your code should invoke javax.persistence.EntityManager.clear() before returning from your DAO. This will detach your entity bean from the persistence context, which will no longer track it. From the java doc:
Clear the persistence context, causing all managed entities to become detached. Changes made to entities that have not been flushed to the database will not be persisted.
If I have nested bean methods which just fetching data from the database. (i.e GET API). So will it be beneficial to mark all bean methods as TransactionAttributeType.NOT_SUPPORTED? Will it help in increase in performance as JTA is not managing any transaction for this?
This is exactly the purpose of using NOT_SUPPORTED, to increase performance. Infact as stated by Oracle:
NotSupported Attribute
If the client is running within a transaction and invokes the
enterprise bean’s method, the container suspends the client’s
transaction before invoking the method. After the method has
completed, the container resumes the client’s transaction.
If the client is not associated with a transaction, the container does
not start a new transaction before running the method.
Use the NotSupported attribute for methods that don’t need
transactions. Because transactions involve overhead, this attribute
may improve performance.
So, it is a perfect fit for all the select or find business methods, which purpose is maybe to fill a data table on screen.
NOT_SUPPORTED is useful if there is a processing that would cause an exception if invoked with transaction context. For example invoking stored procedure containing DDL code withing context of XA processing will cause an exception to occur. If changing stored procedure is not an option use NOT_SUPPORTED attribute as work around and suspend the transaction prior to invocation of method containing problematic stored procedure.
If transaction roll back is allowed in read only transaction use SUPPORTS , if transaction roll back is not allowed in read only transaction use NOT_SUPPORTED.
This article says:"No, it doesn't make sense to use the NOT_SUPPORTED transaction propagation for read-only queries". It's written Vlad Mihalcea who is a JPA expert.
Does TransactionAttributeType.NOT_SUPPORTED make sense for retrieving entities?
I would like to make this question as generic as possible without submitting extensive code and configuration samples so that answer submitters can cover a wide range of possibilities, therefore make it somewhat "academic".
I have two entity classes, Foo and Bar. They are wired to the persistence store (in my case PostgreSQL but I think that shouldn't matter) using JPA with Hibernate as the provider. They are managed by FooDao and BarDao respectively and both DAOs extend a BaseDao which contains a save method:
public T save(T object)
{
return (T) hibernateTemplate.merge(object);
}
which neither DAO overrides (meaning they use the superclass method as is).
The problem is, when I call myFooDao.save(myFoo), it actually persists the objects to the DB but when I call myBarDao.save(myBar), the object is not persisted, YET NO EXCEPTION IS THROWN.
All of this runs out of a Spring context and both DAOs are injected. I should also add both tables have primary keys each tied to its own sequence. While the Bar insertion never actually gets persisted, the associated sequence does get incremented every time, which is odd. So Hibernate does prepare a transaction but getting the next value from the sequence, which increments the sequence, but the new row never shows in the datable.
I am looking to explore some general circumstances under which anomaly can occur. For one, could it be that the configuration is set so that Foo is auto-committed but Bar is not and I should dive into the context configs to find discrepancies? Or could it be that Hibernate thinks the write is successfully committed because the DB engine does not report a failure properly?
Hibernate does not necessarily persist your changes after each updating query (saveOrUpdate, merge for instance).
Its behavior toward persistency is defined by the FlushMode of the Session tied to your HibernateTemplate. The possible FlushModes are described here : https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/FlushMode.html
By default, an Hibernate Session is setted to FlushMode.AUTO. It means that if not absolutly and explictly needed by following queries (to maintain database consistency), no persistent changes are done, except allocation of id by iterating sequences.
It is the result you observed.
To answer your question, if you want to persist your change immediatly after a merge, you will need either :
1) Changing the flush strategy of the Session tied to you HibernateTemplate to "ALWAYS" before merging (or when instanciating the HibernateTemplate).
hibernateTemplate.setFlushModeName("FLUSH_ALWAYS");
2) Explicitly flushing the Session after merging.
hibernateTemplate.flush();
But you should also note that HibernateTemplate is a deprecated approach to interact with databases using Hibernate, in particular because HibernateTemplate does not lead people to properly deal with database transactions.
In the first place, your merge used in a transaction would have automatically been persisted when the transaction is committed with FlushMode.AUTO.
In a Spring application, you could use a #Transactional annotation, which implicitly executes all the logic included in the annotated method through a transaction.
#Autowired
private SessionFactory sessionFactory;
#Transactional
public void doUpdate(Object myObject) {
Session hibSession = sessionFactory.getCurrentSession();
hibSession.merge(myObject);
}
See the complete explanation about Spring transaction management here : http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html (16.5.6 paragraph for #Transactional annotation).
What is the state of your entity at the time of merge? If the entity is in the persistence context (e.g. the session), then an update will occur, if there are any changes made to the object. (if no change, Hibernate will quietly ignore the merge.)
If the entity is not in the persistence context, but it is stored in the DB, then a new row will be inserted, so you'll have duplicate.
Also, please ensure that you are implementing equals() and hashCode() methods for your entity.
We are working on a little web (will run on Tomcat) with the data layer done with JPA (Eclipselink).
I did similar thing some time ago. But i were always unsure when i need to begin and end transactions or do a flush.
At the moment i use transaction if i add (persist) and remove objects. If i call setters on an already persisted object i do not use transactions.
Is there a guide/ tutorial or a short answer when to use transactions or how to implement application managed JPA correctly.
I think one can summarize an answer to your question.
almost any JPA operation needs a transaction, except find/selects that do not lock entities (i.e any JPA operation that does not change the data).
(JTA transaction-scoped entity manager)
In the case of an JTA transaction-scoped entity manager it is better to quote from the spec (Chapter 3 Entity Operations):
The persist, merge, remove, and refresh methods must be invoked within
a transaction context when an entity manager with a
transaction-scoped persistence context is used.
If there is no transaction context, the javax.persistence.TransactionRequiredException is thrown.
Methods that specify a lock mode other than LockModeType.NONE must be invoked
within a transaction context.
If there is no transaction context, the javax.persistence.TransactionRequiredException is thrown.
The find method (provided it is invoked without a lock or invoked with
LockModeType.NONE) and the getReference method are not required to be
invoked within a transaction context. If an entity manager with
transaction-scoped persistence context is in use, the resulting
entities will be detached; if an entity manager with an extended
persistence context is used, they will be managed. See section 3.3 for
entity manager use outside a transaction.
(Application-managed/resource-local entity manager)
In the case of an Application-managed entity manager, the JPA spec is not clear about the behavior. In the case of Hibernate, it is pretty complicated what happens, when not inside a transaction (it could depend also on the JDBC driver and the autocommit mode of the DB connection). Check Hibernate's article on this theme. Basically you are strongly encouraged to always use transactions for the above mentioned operations.
To the second part of your question: if you called a setter of a managed entity, and without flushing you detached it (i.e before transaction commit), the behavior is unclear/undefined, i.e you should better correct the code.
Example of buggy code:
//begin Transaction
MyEntity entity = em.find(MyEntity.class, 1L);
entity.setField("New value");
em.detach();//it is not sure whether the "New value" will be persisted. To make sure it is persisted, ypu need to call em.flush() before detaching
//commit Transaction
Usually if the order of DB operations (not the same as the order of enity manager operations) is not important, you can leave the JPA implementation to decide when to flush (e.g on transaction commit).
I have an EJB where I am saving an object to the database. In an example I have seen, once this data is saved (EntityManager.persist) there is a call to EntityManager.flush(); Why do I need to do this? The object I am saving is not attached and not used later in the method. In fact, once saved the method returns and I would expect the resources to be released. (The example code does this on a remove call as well.)
if (somecondition) {
entityManager.persist(unAttachedEntity);
} else {
attachedEntityObject.setId(unAttachedEntity.getId());
}
entityManager.flush();
A call to EntityManager.flush(); will force the data to be persisted in the database immediately as EntityManager.persist() will not (depending on how the EntityManager is configured: FlushModeType (AUTO or COMMIT) by default is set to AUTO and a flush will be done automatically. But if it's set to COMMIT the persistence of the data to the underlying database will be delayed until the transaction is committed.
EntityManager.persist() makes an entity persistent whereas EntityManager.flush() actually runs the query on your database.
So, when you call EntityManager.flush(), queries for inserting/updating/deleting associated entities are executed in the database. Any constraint failures (column width, data types, foreign key) will be known at this time.
The concrete behaviour depends on whether flush-mode is AUTO or COMMIT.
So when you call EntityManager.persist(), it only makes the entity get managed by the EntityManager and adds it (entity instance) to the Persistence Context. An Explicit flush() will make the entity now residing in the Persistence Context to be moved to the database (using a SQL).
Without flush(), this (moving of entity from Persistence Context to the database) will happen when the Transaction to which this Persistence Context is associated is committed.
The EntityManager.flush() operation can be used the write all changes to the database before the transaction is committed. By default JPA does not normally write changes to the database until the transaction is committed. This is normally desirable as it avoids database access, resources and locks until required. It also allows database writes to be ordered, and batched for optimal database access, and to maintain integrity constraints and avoid deadlocks. This means that when you call persist, merge, or remove the database DML INSERT, UPDATE, DELETE is not executed, until commit, or until a flush is triggered.
EntityManager.flush() sends actual SQL commands to DB.
Persistence framework usually manages transactions behind the scene. So there is no guaranty that flushed queries will be successfully committed.
EntityManager.flush() is always called just before the transaction commit by persistence framework automatically behind the scene.
EntityManager.persist() only registers an entity to persistence context without sending any SQL statements to DB. That means you won't get auto generated IDs after persist(). You just pass persisted object and eventually after later flush() it gets ID. You can call flush() yourself to get those IDs earlier. But again it is not the end of transaction so it can be rolled back and even more: changes might be seen (via phantom reads) by other transactions/thread/processes/servers and then disappear depending on DB engine and isolation level of current and foreign transaction!