hibernate的懒加载有多种解决方式,这里是我使用的其中一种。
hibernate版本:5.2.9.FINAL
场景:有一个记录用户信息的user表,还有一个部门表department,user表里有一个外键字段department_id 对应department表的id,表示该用户所在的部门。因此hibernate的实体类中,User类有一个成员变量是department。
在DAO类中有一个方法根据用户id获取用户信息和该用户所在的部门信息:
User user = (User)session.get(Useer.class.getName(),id); return user;
由于hibernate的懒加载特性,user.getDepartment()获取到的是一个代理对象。如果通过反射将user转换为json对象时会出错,因为user的department变量时一个代理对象。如果在dao的方法里调用user.getDepartment().getName()等方法,是可以的,但是department仍然是一个代理对象。而且由于我将dao的查询方法纳入了spring事务管理,如果对department单独进行一次查询,如:
User user = (User)session.get(User.class.getName(),id);
Department department = (Department) session.get(Department.class.getName(),id); return user;department对象仍然是一个代理对象,并且与user.getDepartment()获取到的Department对象是一个实例。这是因为开启了事务管理的原因,整个方法是一次事务,对同一条department数据的查询,在第一次对User进行查询时实际已经存入了hibernate缓存中,无论进行多少次都是hibernate缓存中的一个代理对象。
现在的问题是要把Deparment对象转换为实际的对象,因此采用这样的方法:
方法一:
User user = (User)session.get(Useer.class.getName(),id);
session.clear();
Department department = (Department) session.get(Department.class.getName(),id); return user;使用session.clear()方法,清空缓存中的对象,因此对Department对象的查询是再次在数据库执行一次语句。
方法二:
String hql = "select u,u.department from User u where u.id = ?"; Query<Object[]> query = session.createQuery(hql); query.setParameter(0, id); Object[] objs = query.uniqueResult(); User user = (User) objs[0];
return user;通过联表查询,由于查询语句中也查询了department对象,hibernate不会对user中的department对象进行懒加载放置到缓存中,而是直接查询并返回一个Department实例。并和user一起填充到一个数组中,此时并不需要从数组中取出Department对象,因为user中的Department对象和数组中的Department对象是一个实例,直接返回user即可。
User user = (User)session.get(Useer.class.getName(),id); return user;