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).
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.
I have the method below.
public Profile readUser(String email){
EntityManager em = EMF.get().createEntityManager();
return em.find(Profile.class, email);
}
Is the above usage of entity manager okay? Or It is necessary to close em?Any suggestions please.
I suppose the answer is: it depends.
Your entity manager is the key to gain access to the context where entities reside. If your application is a JSE application, you have to consider what is the life expectancy of your context.
Let's consider that you will create an entity manager per user's request. So, while you are attending a given request, you will keep your entity manager open, and when you finish with it, you close it.
In a JSE application, you may have considered that you would like to keep your entity manager open the entire life of the application (supposing you're not dealing with big amounts of data) then you close it when your application shuts down.
Bottom line, when you open it and when you close depends entirely on your strategy and your design. You close it when you no longer need the entities in its context.
In your example, that is not evident, but since you're creating the EM in the method, you should close it before returning, otherwise, you will no longer have access to it again (unless you're keeping it in some registry, which is not evident in the code).
If you don't close it your entities will be kept as attached, even after you're done using them. Your context will be kept alive even when you can no longer access your EM.
The JPA Specification contains more details. In section 7.7 Application-managed Persistence Contexts it says:
When an application-managed entity manager is used, the application
interacts directly with the persistence provider's entity manager
factory to manage the entity manager lifecycle and to obtain and
destroy persistence contexts.
All such application-managed persistence contexts are extended in
scope, and can span multiple transactions.
The EntityManagerFactory.createEntityManager method and the
EntityManager close and isOpen methods are used to manage the
lifecycle of an application-managed entity manager and its associated
persistence context.
The extended persistence context exists from the point at which the
entity manager has been created using
EntityManagerFactory.createEntityManager until the entity manager is
closed by means of EntityManager.close.
An extended persistence context obtained from the application-managed
entity manager is a stand-alone persistence context it is not
propagated with the transaction.
[...] The EntityManager.close method closes an entity manager to
release its persistence context and other resources. After calling
close, the application must not invoke any further methods on the
EntityManager instance except for getTransaction and isOpen, or
the IllegalStateException will be thrown. If the close method is
invoked when a transaction is active, the persistence context remains
managed until the transaction completes.
The EntityManager.isOpen method indicates whether the entity manager
is open. The isOpen method returns true until the entity manager has
been closed.
To actually understand how this works it is vital to understand the relationship between the entity manager and the context.
So, as you can see the entity manager is the public interface through which you access your entities, however, your entities reside in a context, attached to your entity manager. Understanding the life cycle of the different types of contexts will answer your question.
Persistence contexts can be of different types. In Java EE applications, you can either have a transaction-scoped persistence context or a extended-persistence context. In the JSE application, the nature of the context is controlled by the developer.
When you ask for an entity to your entity manager, it looks for the entity in its attached context, if it finds the entity there, then it returns it, otherwise, it retrieves the entity from the database. Subsequent calls for this entity in context will return the same entity.
Transaction-scoped
In a Java EE application using the transaction-scoped persistence context, when you first access your entity manager, it checks if the current JTA transaction has a context attached if no context is yet present, a new context is created and the entity manager is linked to this context. Then the entity is read from the database (o from the cache if present) and it is placed into the context. When your transaction ends (commit or rollback), the context becomes invalid and whatever entities in it become detached. This is the classical scenario for stateless sessions beans.
#PersistenceContext(unitName="EmplService")
EntityManager em;
This also means that depending on how you design your transactions, you may end up with more than one context.
Extended-Persistence Context
In a Java EE application with stateful session beans you might like the context to survive multiple bean invocations, since you don't like to commit until the bean has been marked for removal, right? In those cases, you need to use an extended persistence context. In this case, the persistence context is created when it is first needed, but it won't become invalid until your mark the stateful bean for removal.
#PersistenceContext(unitName="EmplService", type=PersistenceContextType.EXTENDED)
This means that, regardless of the instance of the entity manager that gets injected into this bean in subsequent calls of the stateful session beans methods, you can be sure you will always access the same context, and therefore, even subsequent calls will return the same instance, because it is the same context.
Also, your changes will not be flushed until the bean is marked for removal or you manually flush them.
Application-Managed
You can always instantiate manually your entity manager factory and your entity manager. This is what you would typically do in a JSE application, is that right?
For this kind of applications you typically do not have a container to deal with the JTA transactions, right? So you use resource-local transactions and you are responsible for manually committing or rolling back changes.
For this kind of application, when you instantiate your entity manager, a context is automatically attached to it.
Depending on your application, you can decide to create a global entity manager whose life cycle is attached to the life of the application itself. That is a single entity manager for the entire life of the application. In this cases, your context will be created and destroyed with your entity manager.
Or, you could create an entity manager per conversation (i.e. transaction) with your application user. The scope, in this case, is determined by you, but still, your context will be created and destroyed with your entity manager.
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.