I have two entities:
#Entity
public class Entity1{}
#Entity
public class Entity2{
#OneToOne
protected Entity1 e1;
}
I have one method to search for Entity1
Entity1 findEntity1(some args){
EntityManager em = this.emfp.getEntityManager();
//perform search
return e1;
}
I use this method to find Entity2
Entity2 findEntity2(some args){
EntityManager em = this.emfp.getEntityManager();
e1 = findEntity1(args);
//perform search using e1 : Entity2.e1 = e1
return e2;
}
Each method has it's own EntityManager and therefore it's own Persistence context.
Could I use e1, returned from first method, in my second method?
While you cannot do it the way you are describing it - having different persistence contexts, you could do some tweaks to the code, effectively putting the entities in the same context. It depends on your stack if you can use all of them:
For an Java EE application, start the search from a session bean and use a container-managed EntityManager - this will wrap the persistence context in a transaction and both entities will be kept in the same context for the duration of the transaction.
For a Java SE application, you could still use transactions - UserTransactions. You would need to control the span of the transaction manually though.
Use an EXTENDED persistence context (since JPA 2.0). It only gets invalidated explicitly, so all the fetched entites will remain inside the context until you say so.
For all these solutions, you would need to change the EntityManager retrieval. Use the #PersistenceContext annotation in Java EE context and
#PersistenceUnit to retrieve the EntityManagerFactory in SE context
EDIT: It does not matter in how many EJBs you divide the search as long as you are staying inside the same transaction. As a rule of thumb, a transaction starts when the first EJB method is called and ends when this method returns. All methods invoked by this method will be in the same transaction.
This default behaviour may change though - the transactionality of EJB methods is defined by
#TransactionAttribute annotations, so simply follow the path of the call along your beans.
no, you can't use an entity from a different persistence context.
You'll need to expand the the select query and use basic types such as numeric ids or strings.
Related
I can't find information about relationship between EntityManager and transactions in spring data jpa application.
Which one of the statements is correct:
new instance of EntityManager is created per transaction
one shared instance of EntityManager is used for all transactions
The correct answer is: one shared instance of EntityManager is used for all transactions in the same persistence context.
We can have in consideration two things here:
First, the definition in the EntityManager Interface
An EntityManager instance is associated with a persistence context. A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed.
The set of entities that can be managed by a given EntityManager instance is defined by a persistence unit. A persistence unit defines the set of all classes that are related or grouped by the application, and which must be colocated in their mapping to a single database.
Second, the constructor of the Spring SimpleJpaRepository:
public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
Assert.notNull(entityInformation, "JpaEntityInformation must not be null!");
Assert.notNull(entityManager, "EntityManager must not be null!");
this.entityInformation = entityInformation;
this.em = entityManager;
this.provider = PersistenceProvider.fromEntityManager(entityManager);
}
em is an attribute defined in that class with the final modifier:
private final EntityManager em;
And in the methods of the SimpleJpaRepository are made calls to that em without create new instances of the EntityManager.
I want to understand caching in JPA 2 using EclipseLink as persistence provider. I don't know if my my thinking is correct.
For example:
I use JTA transactions. On some entity class called A I have declared #Cacheable(true) annotation. I invoke a method from EJB bean which updates A.class object. On the first I invoke em.find(A.class, 1). My question is what is the searching order. I present my way of thinking.
EntityManager searches entity in the L2 cache. If EM find the object, it copy the object to the L1 cache and stops searching.
Else EntityManager searches entity in the L1 cache. If EM find the object, it stops searching.
Else EntityManager searches entity in database. If EM find the object, it put the object to the L1 cache and stops searching.
When I find object, I modify a few fields and I want to invoke em.merge(aClassRepresentant). I think that when the transactions stops EntityManager puts merged aClassRepresentant to the L2 cache and destroys itself. Do I think correctly?
Hy,
I am having a "Solve failed to lazily initialize a collection of role.... exception" in jpa. I understand that outside a session, when you want to retrieve a lazy collection if there is not session bound you will get this error, fine. But what I dont understand is if I have this spring controller(the code is not 100% correct, is just to explain my case):
#Controller
#Autowired
EnterpriseService enterpriseService ;
public List<Enterprise> getAll(){
List<Enterprise> enterprises = enterpriseService.getAll();
for(Enterprise enterprise:enterprises){
enterprise.getEmployees();
}
return enterprises;
}
When I call "enterprise.getEmployees()", I know there is not anymore a session but why when I try to do "enterprise.getEmployees()", why enterprise is treated like a jpa entity and not just like a normal bean?, I mean; for what I understand a jpa entity is treated like this inside a session but outside like in this case it should be treated like a normal java bean so the calling to enterprise.getEmployees() should be treated like the calling of a get method of a java bean and should not throw any lazy exception....
Maybe is because spring controller treats the enterprise objects like jpa entities and not just only like java beans? this behaviour is specific to spring controllers?
Thanks
An entity returned from an EntityManager is not necessarily an instance of your entity class, but a proxy class which extends your class. In many cases the same is true for the persistent properties of such entities (especially for those annotated with (One/Many)To(One/Many)).
For example if you are using field based access:
#Entity
public class Enterprise {
#OneToMany
private List<Employee> employees = new ArrayList<>();
public List<Employee> getEmployees() {
return employees;
}
}
Here the JPA provider will create a proxy class that extends Enterprise and remembers the previous state from the DB somehow. In addition it will change the employees list to its own implementation of List (which does not need to extend ArrayList).
Because the proxy class can "overwrite" your methods, it could know when you are calling getEmployees() and check for the session. But I don't think that this would happen here, as the method is not annotated with any JPA specific annotation.
In addition some frameworks like Hibernate do support byte code enhancement or byte code instrumentation. That changes the implementation of your class (in byte code) and replaces every access to employees with some provider specific code. I don't know if Spring JPA provides this, but this could lead to check for a session.
Otherwise any call to enterprise.getEmployees() should just return the current value of employees - without any check for the session and without the LazyInitializationException.
But calling enterprise.getEmployees().size() will try to initialize the list and check for the session - this could lead to the mentioned exception.
If you are using property based access things are a little bit different:
#Entity
public class Enterprise {
private List<Employee> employees = new ArrayList<>();
#OneToMany
public List<Employee> getEmployees() {
return employees;
}
}
Here the proxy class will not delegate to your implementation, but overwrite the getEmployees() method and return its own List implementation, without changing employees. Thus here it is possible to get a LazyInitalizationException for enterprise.getEmployees().
Remark: This describes how most JPA implementations are working - but as this is implementation specific some unusual frameworks could do things differently.
It can't do anything else. The only alternative would be to return an empty collection of employees, which would be much much worse: you would incorrectly assume that the enterprise has 0 employee, which is a valid, but completely incorrect result.
To realize how much worse it would be to do that, let's imagine a HospitalAnalysis entity, having a collection of DetectedDisease entities. And let's say you try to display the result of the analysis but forget to initialize the collection. The page would tell you that you're perfectly healthy and that you can safely go home, whereas in reality, you have a cancer, and the program has a bug. I'd much prefer the program to crash with an exception and be fixed rather than not starting my treatment.
Trying to access employees without having initialized the collection, and thus without knowing the actual collection of employees, is just a bug. This bug is signalled by throwing a runtime exception.
My question is about the need to define a UserTransaction in a JSF Bean if multiple EJB methods are called.
This is my general scenario:
//jsf bean...
#EJB ejb1;
...
public String process(businessobject) {
ejb1.op1(businessobject);
ejb1.op2(businessobject);
....
}
both ejbs methods manipulate the same complex jpa entity bean object (including flush and detachment). I recognized in the database that some of the #oneToMany relations form my entity bean where duplicated when ejb1.op1() is called before ejb1.op2().
I understand that both ejbs start a new transaction. And to me anything looks ok so far.
But the JSF code only works correctly if I add a UserTransaction to my jsf method like this:
//jsf bean...
#Resource UserTransaction tx;
#EJB ejb1;
...
public String process(businessobject) {
try {
tx.begin();
ejb1.op1(businessobject);
ejb1.op2(businessobject);
finaly {
tx.commit();
}....
}
I did not expect that it is necessary to encapsulate both ejb calls into one usertransaction. Why is this necessary?
Each #Stateless EJB method call from a client (in your case, the JSF managed bean), counts by default indeed as one full transaction. This lasts as long as until the EJB method call returns, including nested EJB method calls.
Just merge them both into a single EJB method call if it must represent a single transaction.
public String process(Entity entity) {
ejb1.op1op2(entity);
// ...
}
with
public void op1op2(Entity entity) {
op1(entity);
op2(entity);
}
No need to fiddle with UserTransaction in the client. In a well designed JSF based client application you should never have the need for it, either.
As to the why of transactions, it locks the DB in case you're performing a business action on the entity. Your mistake was that you performed two apparently dependent business actions completely separately. This may in a high concurrent system indeed cause a corrupted DB state as you encountered yourself.
As to the why of transactions, this may be a good read: When is it necessary or convenient to use Spring or EJB3 or all of them together?
Is a user transaction needed for you? Generally, container managed transactions are good enough and serve the purpose.
Even if you need to have user managed transactions, it is not a good to have transaction management logic mingled with JSF logic.
For using container managed transactions, you should look at using the #TransactionAttribute on the EJBs.
If all the methods in your ejb need to have the same level of transaction support, you could have the annotation at the class level. Else you could also use the #TransactionAttribute annotation against each individual ejb method.
I am using JPA and lets say I do something like this
public class MoRun extends Thread {...
public void run() {
final EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("pu");
EntityManager manager = emFactory.createEntityManager();
manager.setFlushMode(FlushModeType.COMMIT);
someMethod(manager);
...
}
public void someMethod(EntityManager manager){
Query query = manager.createNamedQuery("byStates");
List<State> list = query.getResultList();
for (State state : list) {
if(someTest)
state.setValue(...)
}
...
}
So for those objects that pass "someTest" and values are updated are those changes automatically persisted to the db even though there is no transaction and I don't explicitly "manager.save(state)" the object? I ask because it seems like it is and I was wondering if the flush is doing it?
According to the javadoc of FlushMode (I'm assuming this is a JPA 1.0 question), and as pointed out by #Konrad:
If there is no transaction active, the persistence provider must not flush to the database.
Since you're very likely using a transaction-type="RESOURCE_LOCAL" for your persistence unit, since I don't see any begin/commit surrounding your calls to your EntityManager (which is not good, more on this just after), for me there is no transaction active so I wouldn't expect anything to be flushed.
Anyway, as reminded in the nice JPA Concepts page:
With <persistence-unit transaction-type="RESOURCE_LOCAL">
you are responsible for EntityManager
(PersistenceContext/Cache) creating
and tracking...
You must use
the EntityManagerFactory to get an
EntityManager
The resulting
EntityManager instance is a
PersistenceContext/Cache
An
EntityManagerFactory can be injected via the
#PersistenceUnit annotation only (not #PersistenceContext)
You are
not allowed to use #PersistenceContext to refer to a unit
of type RESOURCE_LOCAL
You
must use the EntityTransaction API to begin/commit around every call to your
EntityManger
Calling
entityManagerFactory.createEntityManager()
twice results in two separate
EntityManager instances and therefor
two separate PersistenceContexts/Caches.
It is
almost never a good idea to have more than one instance of an
EntityManager in use (don't create a
second one unless you've destroyed the
first)
So, in my opinion, you should fix your code here, there is no real point at wondering about unexpected behavior if your code is not correct. Just performs calls to your EntityManager inside a transaction.
How do you know there is no transaction? Are you using it from EJB? In that case I bet there is a transaction.
From docs (http://java.sun.com/javaee/6/docs/api/javax/persistence/FlushModeType.html):
If FlushModeType.COMMIT is set, the
effect of updates made to entities in
the persistence context upon queries
is unspecified.
If there is no transaction active, the
persistence provider must not flush to
the database.
If you are in transaction, attached entities (i.e. those loaded in the same transaction) are automatically recorded to database.