Hibernate执行太多查询

chr*_*isw 4 java database orm hibernate

我相信我误解了如何选择和渴望工作; 我的目标是在遇到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;
}
Run Code Online (Sandbox Code Playgroud)

然后我填写了一些样本测试数据: -

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);
Run Code Online (Sandbox Code Playgroud)

这可以运行几次以提供一些数据.

然后我执行以下操作: -

session.createQuery("FROM Employee e INNER JOIN e.employeeAreas ea INNER JOIN ea.area").list();
Run Code Online (Sandbox Code Playgroud)

我加入JOIN的原因是我可以进行专业搜索.我在看标准,但似乎它不允许我用WHERE做我能做的一切

我希望它最多可以进行3次查询和2次子查询.

  1. SELECT*FROM Employee INNER JOIN EmployeeArea ON条件INNER JOIN区域ON条件
  2. SELECT*FROM Employee WHERE employeeId IN(子查询1)
  3. SELECT*FROM Area WHERE areaId IN(子查询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
                )
            )
Run Code Online (Sandbox Code Playgroud)

然后是一个非常相似的区域.

我的目标是能够使用返回列表中的每个员工对象来识别工作区域.每个实体中会有更多字段,但是这个测试用例已经简化了.

chr*_*isw 5

我解决了这个问题; 这是我的联接表的一个问题.请参阅以下内容: -

@Id
@ManyToOne
public Employee employee;

@Id
@ManyToOne
public Area area;
Run Code Online (Sandbox Code Playgroud)

我使用了@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();
Run Code Online (Sandbox Code Playgroud)

虽然能够在其中一个连接表列上使用WHERE.