I have a class, Student and the generated Endpoint class for it. ListStudents and insertStudents methods work without any problems, but update and remove don't cause any change in the datastore. The methods don't throw any errors and the call returns, but no changes are made.
My endpoints code is mostly the code generated by google plugin for eclipse:
#ApiMethod(name = "removeStudent", path="remove_student")
public void removeStudent(#Named("email") String email) {
EntityManager mgr = getEntityManager();
try {
Student student = getStudentByEmailName(email);
mgr.remove(student);
} finally {
mgr.close();
}
}
Entitiy manager getter method:
private static EntityManager getEntityManager() {
return EMF.get().createEntityManager();
}
#ApiMethod(name = "updateStudent")
public Student updateStudent(Student student) {
EntityManager mgr = getEntityManager();
try {
if (!containsStudent(student)) {
throw new EntityNotFoundException("Object does not exist");
}
mgr.persist(student);
} finally {
mgr.close();
}
return student;
}
And my EMF class:
public final class EMF {
private static final EntityManagerFactory emfInstance = Persistence
.createEntityManagerFactory("transactions-optional");
private EMF() {
}
public static EntityManagerFactory get() {
return emfInstance;
}
}
The client that uses this endpoint is Android. I have only tried testing on my local server.
Please tell me if I'm doing something wrong. Thank you
Do you have your student entities indexed by email?
This is a typical issue when you move to nosql and expect all queries to work without indexes.
Note that records inserted before defining index would not be in index.
The datastore is eventually consistent and your code should work. What is the return value that you get in the Student object from your updateStudent method.
As much as I don't want to, after you do a mgr.persist(...) , add mgr.flush() and see if that makes a difference.
I get the following exception:
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at sei.persistence.wf.entities.Element_$$_jvstc68_47.getNote(Element_$$_jvstc68_47.java)
at JSON_to_XML.createBpmnRepresantation(JSON_to_XML.java:139)
at JSON_to_XML.main(JSON_to_XML.java:84)
when I try to call from main the following lines:
Model subProcessModel = getModelByModelGroup(1112);
System.out.println(subProcessModel.getElement().getNote());
I implemented the getModelByModelGroup(int modelgroupid) method firstly like this :
public static Model getModelByModelGroup(int modelGroupId, boolean openTransaction) {
Session session = SessionFactoryHelper.getSessionFactory().getCurrentSession();
Transaction tx = null;
if (openTransaction) {
tx = session.getTransaction();
}
String responseMessage = "";
try {
if (openTransaction) {
tx.begin();
}
Query query = session.createQuery("from Model where modelGroup.id = :modelGroupId");
query.setParameter("modelGroupId", modelGroupId);
List<Model> modelList = (List<Model>)query.list();
Model model = null;
for (Model m : modelList) {
if (m.getModelType().getId() == 3) {
model = m;
break;
}
}
if (model == null) {
Object[] arrModels = modelList.toArray();
if (arrModels.length == 0) {
throw new Exception("Non esiste ");
}
model = (Model)arrModels[0];
}
if (openTransaction) {
tx.commit();
}
return model;
} catch(Exception ex) {
if (openTransaction) {
tx.rollback();
}
ex.printStackTrace();
if (responseMessage.compareTo("") == 0) {
responseMessage = "Error" + ex.getMessage();
}
return null;
}
}
and got the exception. Then a friend suggested me to always test the session and get the current session to avoid this error. So I did this:
public static Model getModelByModelGroup(int modelGroupId) {
Session session = null;
boolean openSession = session == null;
Transaction tx = null;
if (openSession) {
session = SessionFactoryHelper.getSessionFactory().getCurrentSession();
tx = session.getTransaction();
}
String responseMessage = "";
try {
if (openSession) {
tx.begin();
}
Query query = session.createQuery("from Model where modelGroup.id = :modelGroupId");
query.setParameter("modelGroupId", modelGroupId);
List<Model> modelList = (List<Model>)query.list();
Model model = null;
for (Model m : modelList) {
if (m.getModelType().getId() == 3) {
model = m;
break;
}
}
if (model == null) {
Object[] arrModels = modelList.toArray();
if (arrModels.length == 0) {
throw new RuntimeException("Non esiste");
}
model = (Model)arrModels[0];
if (openSession) {
tx.commit();
}
return model;
} catch(RuntimeException ex) {
if (openSession) {
tx.rollback();
}
ex.printStackTrace();
if (responseMessage.compareTo("") == 0) {
responseMessage = "Error" + ex.getMessage();
}
return null;
}
}
}
but still, get the same error.
I have been reading a lot for this error and found some possible solutions. One of them was to set lazyLoad to false but I am not allowed to do this that's why I was suggested to control the session
If you using Spring mark the class as #Transactional, then Spring will handle session management.
#Transactional
public class MyClass {
...
}
By using #Transactional, many important aspects such as transaction propagation are handled automatically. In this case if another transactional method is called the method will have the option of joining the ongoing transaction avoiding the "no session" exception.
WARNING If you do use #Transactional, please be aware of the resulting behavior. See this article for common pitfalls. For example, updates to entities are persisted even if you don't explicitly call save
You can try to set
<property name="hibernate.enable_lazy_load_no_trans">true</property>
in hibernate.cfg.xml or persistence.xml
The problem to keep in mind with this property are well explained here
What is wrong here is that your session management configuration is set to close session when you commit transaction. Check if you have something like:
<property name="current_session_context_class">thread</property>
in your configuration.
In order to overcome this problem you could change the configuration of session factory or open another session and only then ask for those lazy loaded objects. But what I would suggest here is to initialize this lazy collection in getModelByModelGroup itself and call:
Hibernate.initialize(subProcessModel.getElement());
when you are still in active session.
And one last thing. A friendly advice. You have something like this in your method:
for (Model m : modelList) {
if (m.getModelType().getId() == 3) {
model = m;
break;
}
}
Please insted of this code just filter those models with type id equal to 3 in the query statement just couple of lines above.
Some more reading:
session factory configuration
problem with closed session
The best way to handle the LazyInitializationException is to use the JOIN FETCH directive:
Query query = session.createQuery("""
select m
from Model m
join fetch m.modelType
where modelGroup.id = :modelGroupId
"""
);
Anyway, DO NOT use the following Anti-Patterns as suggested by some of the answers:
Open Session in View
hibernate.enable_lazy_load_no_trans
Sometimes, a DTO projection is a better choice than fetching entities, and this way, you won't get any LazyInitializationException.
if you use spring data jpa , spring boot you can add this line in application.properties
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
I was getting the same error for a one to many relationships for below annotation.
#OneToMany(mappedBy="department", cascade = CascadeType.ALL)
Changed as below after adding fetch=FetchType.EAGER, it worked for me.
#OneToMany(mappedBy="department", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
This exception because of when you call session.getEntityById(), the session will be closed. So you need to re-attach the entity to the session. Or Easy solution is just configure default-lazy="false" to your entity.hbm.xml or if you are using annotations just add #Proxy(lazy=false) to your entity class.
I encountered the same issue. I think another way to fix this is that you can change the query to join fetch your Element from Model as follows:
Query query = session.createQuery("from Model m join fetch m.element where modelGroup.id = :modelGroupId")
This means that the object which you are trying to access is not loaded, so write a query that makes a join fetch of the object which you are trying to access.
Eg:
If you are trying to get ObjectB from ObjectA where ObjectB is a foreign key in ObjectA.
Query :
SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB
Faced the same Exception in different use case.
Use Case : Try to read data from DB with DTO projection.
Solution: Use get method instead of load.
Generic Operation
public class HibernateTemplate {
public static Object loadObject(Class<?> cls, Serializable s) {
Object o = null;
Transaction tx = null;
try {
Session session = HibernateUtil.getSessionFactory().openSession();
tx = session.beginTransaction();
o = session.load(cls, s); /*change load to get*/
tx.commit();
session.close();
} catch (Exception e) {
e.printStackTrace();
}
return o;
}
}
Persistence Class
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private int customerId;
#Column(name = "Name")
private String customerName;
#Column(name = "City")
private String city;
//constructors , setters and getters
}
CustomerDAO interface
public interface CustomerDAO
{
public CustomerTO getCustomerById(int cid);
}
Entity Transfer Object Class
public class CustomerTO {
private int customerId;
private String customerName;
private String city;
//constructors , setters and getters
}
Factory Class
public class DAOFactory {
static CustomerDAO customerDAO;
static {
customerDAO = new HibernateCustomerDAO();
}
public static CustomerDAO getCustomerDAO() {
return customerDAO;
}
}
Entity specific DAO
public class HibernateCustomerDAO implements CustomerDAO {
#Override
public CustomerTO getCustomerById(int cid) {
Customer cust = (Customer) HibernateTemplate.loadObject(Customer.class, cid);
CustomerTO cto = new CustomerTO(cust.getCustomerId(), cust.getCustomerName(), cust.getCity());
return cto;
}
}
Retrieving data: Test Class
CustomerDAO cdao = DAOFactory.getCustomerDAO();
CustomerTO c1 = cdao.getCustomerById(2);
System.out.println("CustomerName -> " + c1.getCustomerName() + " ,CustomerCity -> " + c1.getCity());
Present Data
Query and output generated by Hibernate System
Hibernate: select customer0_.Id as Id1_0_0_, customer0_.City as City2_0_0_, customer0_.Name as Name3_0_0_ from CustomerLab31 customer0_ where customer0_.Id=?
CustomerName -> Cody ,CustomerCity -> LA
This means you are using JPA or hibernate in your code and performing modifying operation on DB without making the business logic transaction.
So simple solution for this is mark your piece of code #Transactional
There are several good answers here that handle this error in a broad scope. I ran into a specific situation with Spring Security which had a quick, although probably not optimal, fix.
During user authorization (immediately after logging in and passing authentication) I was testing a user entity for a specific authority in a custom class that extends SimpleUrlAuthenticationSuccessHandler.
My user entity implements UserDetails and has a Set of lazy loaded Roles which threw the "org.hibernate.LazyInitializationException - could not initialize proxy - no Session" exception. Changing that Set from "fetch=FetchType.LAZY" to "fetch=FetchType.EAGER" fixed this for me.
If you are using JPQL, use JOIN FETCH is the easiest way:
http://www.objectdb.com/java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_
In Spring Application Just Add
#Transactional(readOnly = true)
on your Function.
Remind that import spring Transactional annotation
import org.springframework.transaction.annotation.Transactional;
Use #NamedEntityGraph. Eagar fetch will deteriorate the performance. Refer https://thorben-janssen.com/lazyinitializationexception/ for in-depth explanation.
If you are using Grail's Framework, it's simple to resolve lazy initialization exception by using Lazy keyword on specific field in Domain Class.
For-example:
class Book {
static belongsTo = [author: Author]
static mapping = {
author lazy: false
}
}
Find further information here
In my case a misplaced session.clear() was causing this problem.
springBootVersion = '2.6.7'
hibernate = 5.6.8.Final'
For me i get the error in:
MyEntity myEntity = myEntityRepository.getById(id);
I change to this:
MyEntity myEntity = myEntityRepository.findById(id).orElse(null);
and i add #ManyToOne(fetch = FetchType.EAGER) in entity
This happened to me when I was already using #Transactional(value=...) and was using multiple transaction managers.
My forms were sending back data that already had #JsonIgnore on them, so the data being sent back from forms was incomplete.
Originally I used the anti pattern solution, but found it was incredibly slow. I disabled this by setting it to false.
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=false
The fix was to ensure that any objects that had lazy-loaded data that weren't loading were retrieved from the database first.
Optional<Object> objectDBOpt = objectRepository.findById(object.getId());
if (objectDBOpt.isEmpty()) {
// Throw error
} else {
Object objectFromDB = objectDBOpt.get();
}
In short, if you've tried all of the other answers, just make sure you look back to check you're loading from the database first if you haven't provided all the #JsonIgnore properties and are using them in your database query.
All answers about adding JOIN FETCH (or left join fetch) are correct, I want only to add this:
if you have converter be sure the getAsObject sub uses a "find" than includes in the sql the Join Fetch too.
I lost much time to fix a similar problem, and the problem was in the converter.
I was getting this error in my JAX-RS application when I was trying to get all the Departments. I had to add the #JsonbTransient Annotation to the attributes of both classes. My entities are Department and Employee, and the DB relationship is Many to Many.
Employee.java
...
#ManyToMany
#JoinTable(
name = "emp_dept",
joinColumns = {#JoinColumn(name = "emp_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "dept_id", referencedColumnName = "id")}
)
#JsonbTransient
private Set<Department> departments = new HashSet<Department>();
...
Department.java
...
#ManyToMany(mappedBy = "departments")
#JsonbTransient
private Set<Employee> employees = new HashSet<Employee>();
...
uses session.get(*.class, id); but do not load function
you could also solved it by adding lazy=false into into your *.hbm.xml file or you can init your object in Hibernate.init(Object) when you get object from db
Do the following changes in servlet-context.xml
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.enable_lazy_load_no_trans">true</beans:prop>
</beans:props>
</beans:property>
I am moving a JPA-Hibernate application from a Java EE 6 environment to a Tomcat 7 one.
The application has several DAO classes making queries on the EntityManager. In the Java EE environment I could just inject it using the #PersistenceContext annotation, and let the container manage the EntityManager. Now that I have to do it manually, I was wondering what is the way to go.
Should the entity manager be unique? If so can it be a static final field, created on startup and that every DAO class uses? Does it have a lifecycle that involves closing it and then re-opening it?
Unfortunately, you'll have to do it manually. The way I usually do it is to define a special class:
public class EMF {
private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("name");
public static EntityManager getEntityManager() {
return factory.createEntityManager();
}
}
So, every time you need EntityManager, you have to create it manually. You need to handle transactions as well:
EntityManager em = EMF.getEntityManager();
EntityTransaction et = em.getTransaction();
try {
MyEntity my = new MyEntity();
et.begin();
try {
em.persist(my);
et.commit();
} catch (Exception ex) {
if (et.isActive())
et.rollback();
}
} finally {
em.close();
}
In one of our projects user can attach file to his account. We store these files in the MS-SQL database. So, we have the following piece of code:
#Entity
public class File extends AbstractEntity {
#Lob
#Basic
private byte[] data;
#Nullable
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public File() {
}
public File(byte[] data) {
this.data = data;
}
}
public class SomeBean {
#PersistenceContext
protected EntityManager em;
public Long uploadFile(#NotNull byte[] data) {
final PhysicalFile physicalFile = new PhysicalFile();
physicalFile.setData(data);
em.persist(physicalFile);
return physicalFile.getId();
}
}
And all was nice and pretty, before we tried to upload 40 MB file, and got java.lang.RuntimeException: javax.transaction.RollbackException: [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] Can't commit because the transaction is in aborted state, which was caused by java.lang.OutOfMemoryError: Java heap space inside the uploadFile() method.
I made a heap dump and looked at it in VisualVM.
400+ MB of char[] and 100+ MB of byte[]. On the start our application, including JBoss, was using something about 60-65 MB of heap. So, the question is, why EntityManager consumes heap memory like crazy?
My understaning to your issue as follows.
All the entities that load/persist through an EntityManager stay in memory until you explicitly detach the entities from it (via EntityManager.detach() or EntityManager.clear() or EntityManager.close()). So it's better to have short-lived EntityManagers.
As far as a RuntimeException occurs in the business logic, the em
EntityManager remains open! You'll always want to avoid this sort of
code. you can think of creating and closing the EntityManager as
follows:
public Customer getBestCustomerOfMonth() {
EntityManagerFactory emf = ... ;
EntityManager em = emf.createEntityManager();
// business logic
em.close();
}
You can nest the line for closing the EntityManager em.close(); inside a finally
block
when using transactions outside an enterprise application server
because you'll have to close (commit or rollback) the transaction in
the same way you do for EntityMangers. In order for these resources
(both EntityManager and underlying transaction) to be closed you'll
need to make an additional level of nesting and write your code
similar to this one:
public Customer updateCustomer(Customer cust) {
EntityManagerFactory emf = ... ; EntityManager em =
emf.createEntityManager(); try {
EntityTransaction t = em.getTransaction();
try {
t.begin();
// business logic to update the customer
em.merge(cust);
t.commit();
} finally {
if (t.isActive()) t.rollback();
} } finally {
em.close();
}
}
You may think this nested structure could looks like a bit of a mess, but it is really needed in precence of transactions.
I am doing tests on an ejb3-project using ejb3unit session bean test. The following test will fail with the last assertNotSame() check.
public void testSave() {
Entity myEntity = new Entity();
myEntity.setName("name1");
myEntity = getBeanToTest().save(myEntity);
assertNotSame("id should be set", 0l, myEntity.getId());
// now the problem itself ...
int count = getBeanToTest().findAll().size();
assertNotSame("should find at least 1 entity", 0, count);
}
So, what is happening. The save(entity) method delivers my "persisted" object with an id set. But when I'll try to find the object using findAll() it won't deliver a single result. How can I get my ServiceBean.save method to work, so the persisted entity can be found?
Edit
My ServiceBean looks like this
#Stateless
#Local(IMyServiceBean.class)
public class MyServiceBean implements IMyServiceBean {
#PersistenceContext(unitName = "appDataBase")
private EntityManager em;
public Entity save(Entity entity) {
em.merge(entity);
}
public List<Entity> findAll() {
... uses Query to find all Entities ..
}
}
and for ejb3unit the ejb3unit.properties:
ejb3unit_jndi.1.isSessionBean=false
ejb3unit_jndi.1.jndiName=project/MyServiceBean/local
ejb3unit_jndi.1.className=de.prj.MyServiceBean
Here we go..
public void testSave() {
Entity myEntity = .. // create some valid Instance
// ...
EntityTransaction tx = this.getEntityManager().getTransaction();
try {
tx.begin();
myEntity = getBeanToTest().save(myEntity);
tx.commit();
} catch (Exception e) {
tx.rollback();
fail("saving failed");
}
// ...
}
maybe this'll help some of you.
Perhaps you don't have a running transaction, hence your entity isn't saved.
One option is to manually start the transaction by injecting a #PersistenceContext in the test, but better look for automatic transaction management in ejb3unit.