在我的测试中,Hibernate 默认执行 LEFT OUTER JOIN。但是,您可以确保它将始终使用带注释的 LEFT OUTER JOIN。我花了一些时间使用双向一对多映射来模拟您的情况我的模板 https://stackoverflow.com/q/24257449/2357233作为基础,然后更改类名称以符合您的情况。
我想出的课程如下:
职工监事班:
@Entity(name="EMPLOYEE_SUPERVISOR")
public class EmployeeSupervisor {
@Id
@GenericGenerator(name = "gen", strategy = "increment")
@GeneratedValue(generator = "gen")
@Column(name = "id")
private int supervisorId;
@Column
private String name;
@OneToMany(mappedBy = "supervisor")
private List<Employee> employees;
....
}
员工类别:
@Entity
public class Employee {
@Id
@GenericGenerator(name = "gen", strategy = "increment")
@GeneratedValue(generator = "gen")
@Column(name = "id")
private int employeeId;
@Column
private String name;
@ManyToOne
@Fetch(FetchMode.JOIN)
@JoinColumn(name = "supervisorId")
private EmployeeSupervisor supervisor;
....
}
确保您始终使用的注释LEFT OUTER JOIN
is the @Fetch(FetchMode.JOIN
注解。这告诉 Hibernate 使用 a 加载同一个 select 语句中的关联记录LEFT OUTER JOIN
(see 文档 http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch20.html#performance-fetching对于其他类型的FetchMode
以及每个人的作用)。
然后我在 jUnit 中模拟了数据库,配置 Hibernate 以在 log4j 中打印所有生成的 SQL
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.type=TRACE
并运行了一个非常基本的单元测试。
public class EmployeeDAOTest extends SpringTest{
@Autowired
private EmployeeDAO dao;
private Employee testLinkedEmployee;
private Employee testUnlinkedEmployee;
private EmployeeSupervisor testSupervisor;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("Starting DAO Test");
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("Finished DAO Test");
}
@Before
public void setUp() throws Exception {
//Irrelevant horrible setup code snipped.
/* Set up 2 employees and a EmployeeSupervisor in the database.
* Link one employee to the EmployeeSupervisor and not the other
*/
}
@Test
@Transactional
public void test() {
Employee actualLinkedEmployee = dao.getEmployee(testLinkedEmployee.getEmployeeId());
Employee actualUnlinkedEmployee = dao.getEmployee(testUnlinkedEmployee.getEmployeeId());
assertNotNull("The linked employee's supervisor didn't get selected.", actualLinkedEmployee.getSupervisor());
assertNull("The unlinked employee's supervisor was not null.", actualUnlinkedEmployee.getSupervisor());
}
}
我的 DAO 非常初级:
@Repository
public class EmployeeDAOImpl implements EmployeeDAO {
@Autowired
private SessionFactory sessionFactory;
@Override
public Employee getEmployee(int id) {
Criteria query = sessionFactory.getCurrentSession().createCriteria(Employee.class);
query.add(Restrictions.idEq(id));
return (Employee) query.uniqueResult();
}
}
SQL输出如下:
[junit] /* criteria query */ select
[junit] this_.id as id1_1_1_,
[junit] this_.name as name2_1_1_,
[junit] this_.supervisorId as supervis3_1_1_,
[junit] employeesu2_.id as id1_0_0_,
[junit] employeesu2_.name as name2_0_0_
[junit] from
[junit] Employee this_
[junit] left outer join
[junit] EMPLOYEE_SUPERVISOR employeesu2_
[junit] on this_.supervisorId=employeesu2_.id
[junit] where
[junit] this_.id = ? 01:23:54:0.668
[junit] binding parameter [1] as [INTEGER] - 5 01:23:54:0.671
[junit] /* criteria query */ select
[junit] this_.id as id1_1_1_,
[junit] this_.name as name2_1_1_,
[junit] this_.supervisorId as supervis3_1_1_,
[junit] employeesu2_.id as id1_0_0_,
[junit] employeesu2_.name as name2_0_0_
[junit] from
[junit] Employee this_
[junit] left outer join
[junit] EMPLOYEE_SUPERVISOR employeesu2_
[junit] on this_.supervisorId=employeesu2_.id
[junit] where
[junit] this_.id = ? 01:23:54:0.704
[junit] binding parameter [1] as [INTEGER] - 6 01:23:54:0.704
应该注意的是,默认情况下 Hibernate 似乎急切地获取这些实体并使用 LEFT OUTER JOIN 来执行此操作。但是,如果您尝试将默认获取类型设置为FetchType.LAZY
然后连接类型更改为FetchMode.SELECT
并且只为员工发出一个选择,而不选择主管。
Setting FetchType.LAZY
with @Fetch(FetchMode.JOIN)
但是,它会覆盖您的惰性获取并使用连接来急切地获取您的主管。