我相信我误解了如何选择和渴望工作;我的目标是在遇到N + 1问题时提高性能
编辑我想知道我是否会更快地使用create SQL查询方法并自己创建对象,尽管我希望hibernate与性能相提并论。我可以在一个查询中拉回下面的例子中所需的所有数据,那么为什么hibernate会为每个查询执行单独的查询呢?
我创建了以下测试用例来突出我的问题,请原谅这个模型的粗糙..
@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;
}
然后我填写了一些样本测试数据: -
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);
这可以运行几次以提供一些数据。
然后我执行以下操作: -
session.createQuery("FROM Employee e INNER JOIN e.employeeAreas ea INNER JOIN ea.area").list();
我加入JOIN的原因是我可以进行专家搜索。我正在看标准,但似乎它不允许我用WHERE做所有我能做的事
我希望它最多可以进行3次查询和2次子查询。
事实上,对于前面提到的测试数据的6个输入,我似乎为一个员工获得了6个选择,6个选择了一个区域,看起来像我假定的'1'查询。然后是两个看起来完全错误的大型查询: -
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 ) )
然后是一个非常相似的区域。
我的目标是能够使用返回列表中的每个员工对象来识别工作区域。每个实体中会有更多字段,但这个测试用例已经简化。
答案 0 :(得分:5)
我解决了这个问题;这是我的联接表的一个问题。请参阅以下内容: -
@Id
@ManyToOne
public Employee employee;
@Id
@ManyToOne
public Area area;
我使用了@Id导致了抛出的StackOverflowError异常。使用以下查询,在Employee上获取EAGER和@Fetch JOIN的OneToMany,以及在Area上获取LAZY和@Fetch SELECT的OneToMany,然后我可以执行以下查询: -
List<Employee> employees = session.createQuery("FROM Employee e INNER JOIN FETCH e.employeeAreas ea INNER JOIN FETCH ea.area").list();
虽然能够在其中一个连接表列上使用WHERE。
答案 1 :(得分:3)
使用JOIN
策略并将Area
懒惰地链接到EmployeeArea
,而Employee
则急切地加载EmployeeAreas
。当Employee
加载EmployeeArea
时,hibernate会话将填充EmployeeArea
个对象。然后,如果您浏览Employee.EmployeeArea.Area.EmloyeeArea
,将无法从数据库中获取任何内容,因为我们在会话缓存中已经有EmployeeArea
。