Hibernate with too many requests

I believe that I do not understand how the subtitle and impatient work; my goal is to improve performance since I ran into N + 1 problem.

Change I am wondering if it will be easier for me to simply use the SQL query creation method and create the objects myself, although I was hoping that sleep mode would be consistent with performance. I can discard all the data needed in the example below in one request, so why is there a separate request for each in sleep mode?

I created the following test case to highlight my problem, please excuse the rudeness of this model.

@Entity @Table(name = "Area") public class Area implements Serializable { @Id @GeneratedValue(generator = "areaId" ) @GenericGenerator(name = "areaId", strategy = "uuid2") public String areaId; @OneToMany(mappedBy = "area", fetch=FetchType.EAGER) @Fetch(FetchMode.SUBSELECT) public Set<EmployeeArea> employeeAreas = new HashSet<EmployeeArea>(); } @Entity @Table(name = "Employee") public class Employee implements Serializable { @Id @GeneratedValue(generator = "employeeId" ) @GenericGenerator(name = "employeeId", strategy = "uuid2") public String employeeId; @OneToMany(mappedBy = "employee", fetch=FetchType.EAGER) @Fetch(FetchMode.SUBSELECT) public Set<EmployeeArea> employeeAreas = new HashSet<EmployeeArea>(); } @Entity @Table(name = "EmployeeArea") public class EmployeeArea implements Serializable { @Id @GeneratedValue(generator = "employeeAreaId" ) @GenericGenerator(name = "employeeAreaId", strategy = "uuid2") public String employeeAreaId; @Id @ManyToOne public Employee employee; @Id @ManyToOne public Area area; } 

Then I filled in some test data: -

 Employee employee = new Employee(); Area area = new Area(); EmployeeArea employeeArea = new EmployeeArea(); employeeArea.area = area; employeeArea.employee = employee; session.save(employee); session.save(area); session.save(employeeArea); 

This can be run multiple times to provide some data.

Then I do the following: -

 session.createQuery("FROM Employee e INNER JOIN e.employeeAreas ea INNER JOIN ea.area").list(); 

The reason I'm doing a JOIN is because I can do specialized searches. I looked at the criteria, but it seemed that it did not allow me to do everything I could with WHERE

I would expect it to fulfill no more than 3 queries and 2 subqueries.

  • SELECT * FROM Employee INNER JOIN EmployeeArea ON condition INNER JOIN Area ON condition
  • SELECT * FROM Employee WHERE employeeId IN (subquery 1)
  • SELECT * FROM Area WHERE areaId IN (subquery 2)

In fact, for the 6 test data inputs mentioned above, I seem to get 6 samples for the employee, 6 chooses for the area something similar to my supposed query for "1". and then two large queries that seem just wrong: -

 select employeear0_.employee_employeeId as employee2_3_2_, employeear0_.employeeAreaId as employee1_4_2_, employeear0_.employee_employeeId as employee2_4_2_, employeear0_.area_areaId as area3_4_2_, employeear0_.employeeAreaId as employee1_4_1_, employeear0_.employee_employeeId as employee2_4_1_, employeear0_.area_areaId as area3_4_1_, area1_.areaId as areaId1_0_0_ from EmployeeArea employeear0_ inner join Area area1_ on employeear0_.area_areaId=area1_.areaId where employeear0_.employee_employeeId in ( select employee1_.employeeId from EmployeeArea employeear0_ inner join Employee employee1_ on employeear0_.employee_employeeId=employee1_.employeeId where employeear0_.area_areaId in ( select area2_.areaId from Employee employee0_ inner join EmployeeArea employeear1_ on employee0_.employeeId=employeear1_.employee_employeeId inner join Area area2_ on employeear1_.area_areaId=area2_.areaId ) ) 

and then very similar to the area.

My goal is to be able to use each employee object in the returned list to determine the areas in which they worked. Each object would have more fields, but this test case has been simplified.

+4
source share
2 answers

I solved the problem; it was a problem with my join table. See Next: -

 @Id @ManyToOne public Employee employee; @Id @ManyToOne public Area area; 

I used @Id, resulting in a StackOverflowError exception being thrown. Using the following query: using OneToMany to fetch EAGER and @Fetch JOIN on Employee and select OneToMany LAZY and @Fetch SELECT on Area, I can run the following query: -

 List<Employee> employees = session.createQuery("FROM Employee e INNER JOIN FETCH e.employeeAreas ea INNER JOIN FETCH ea.area").list(); 

For now, you can use WHERE in one of the columns in the join table.

+5
source

Use the JOIN strategy and Area link in EmployeeArea lazily, and Employee eagerly loads EmployeeAreas . When Employee loads EmployeeArea , the hibernate session is populated with EmployeeArea objects. Then, if you navigate through Employee.EmployeeArea.Area.EmloyeeArea , nothing will be retrieved from the database because we already have EmployeeArea in the session cache.

+3
source

Source: https://habr.com/ru/post/1486093/


All Articles