Tag Archives: could not initialize proxy – no Session

Analysis and solution of could not initialize proxy – no session exception in JPA

Reprinted from: https://blog.csdn.net/blueheart20/article/details/52912023

Introduction: JPA is a very popular and commonly used persistence framework standard, under which several different implementations can be connected. In different parent-child table management, we often encounter the problem of no session. How to solve it

The introduction of the problem

In the JPA based unit test, we use JUnit to read the association table information of the test database, and the result is as follows:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.rain.wx.meal.model.DishCategory.dishes, could not initialize proxy - no Session
	at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:587)
	at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:204)
	at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:566)
	at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:135)
	at org.hibernate.collection.internal.PersistentBag.get(PersistentBag.java:449)
	at com.rain.wx.meal.service.DishServiceTest.testDishes(DishServiceTest.java:86)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

After analysis, the key words are: could not initialize proxy – no session; Based on the implementation of JPA, when accessing the database, the current access and operation session for the database has been closed and released, so it prompts that no session is available

code implementation analysis

let’s take a look at the specific code

@Entity
@Table(name="dish_category")
@Data
@EqualsAndHashCode(callSuper=false)
@JsonRootName(value="category") 
public class DishCategory extends BaseEntity {
	private static final long serialVersionUID = -7189824224534351030L;
 
	@Column
	private String name;
	
	@Column
	private String description;
	
	
	@OneToMany
	@JoinColumn(name="category_id",referencedColumnName="id")
	private List<MealDish> dishes;
}

The other entity bean is mealdish, and its code is:

@Entity
@Table(name = "dish")
@JsonRootName(value="dish") 
//@Lazy(value=false)
public class MealDish extends BaseEntity {
	private static final long serialVersionUID = -3982356728880195795L;
 
	@Column
	private String name;
 
	@Column
	private float price;
 
	@Column(name = "img_url")
	private String imgUrl;
 
	@Column(name="category_id")
	private long categoryId;
 
	@Column
	private boolean active;
 
	@Column
	private int soldCount;
        .......
}

The codes of repository/service are as follows:

@Service
public class DishServiceImpl implements DishService { 
       @Transactional
	@Override
	public List<DishCategory> getDishCategory() {
		return this.dishCategoryRepo.findAll();
	}
   ........
 }

Repository related code is empty code, no actual implementation, again ignored here

Unit test code content:

 @Test
    public void testDishes() throws JsonProcessingException {
    	ObjectMapper mapper = new ObjectMapper();
    	
    	List<DishCategory> categories = this.dishService.getDishCategory();
    	
    	for (DishCategory category  : categories) {
    	    // log.debug(String.valueOf(category.getDishes().get(0)));	
    	}
    	
    	String jsonStr = mapper.writeValueAsString(categories);
    	
    	log.info(jsonStr);
    }

Problem analysis

Based on the understanding of hibernate and JPA, in ORM, lazy loading is used in order to improve the performance, that is, additional data will be loaded when it is used. As a result, the session fails when the data is loaded again when it is used. So the goal of the problem is to load the data ahead of time

solution to the problem

try 1: add @ transactional to the service method to add transactions

result 1: invalid

try 2: on the @ onetomany method, Use @ lazy (false)

result 2: invalid

try 3: use fetch = fetchtype = Eagle

in the parameter of @ onetomony result 3: problem solving

try 4: add spring.jpa.open-in-view = true

in the configuration file of application.properties result 4: correct code content of problem solving

method 3:

@Entity
@Table(name="dish_category")
@Data
@EqualsAndHashCode(callSuper=false)
@JsonRootName(value="category") 
public class DishCategory extends BaseEntity {
	private static final long serialVersionUID = -7189824224534351030L;
 
	@Column
	private String name;
	
	@Column
	private String description;
	
	
	@OneToMany(fetch=FetchType.EAGER)
	@JoinColumn(name="category_id",referencedColumnName="id")
	private List<MealDish> dishes;
}

Explanation and explanation of method 4:

This setting option:

spring.jpa.open-in-view=true

In fact, the previous openentitymanagerinview interceptor solved the problem of declaration cycle of session between spring MVC and JPA

summary

the core problem is to solve the problem of delayed loading. In order to load in time, loading in time will consume a certain amount of resources. Please pay attention to the problem of reducing the performance of the program