Hibernate的懒加载详解

来源:互联网 发布:linux安装qemu 编辑:程序博客网 时间:2024/06/09 20:05

一、首先了解几个问题:

1、什么是懒加载?

所谓懒加载也就是延迟加载。


2、什么时候使用懒加载?

当我们去查询某项数据,此项数据有与其关联的数据,而对于所关联的数据,我们并不确定是否需要,此时就可以使用懒加载,来减少不必要的内存消耗,让数据在真正使用的时候才去加载。

比如:Department和Employee。部门与员工是1对多的关系,如果不进行懒加载,那么只要加载一个部门,就会根据此部门来加载所有的员工,但实际上,我们只是需要用到部门的信息,而将员工信息也加载进内存显然就造成了浪费。如果我们设置成懒加载,那么只有你在具体的使用带员工的信息的时候才会去加载员工的信息。


3、Hibernate中懒加载的实现:

hibernate的懒加载是利用动态代理来实现的;我们知道动态代理有JDK的动态代理(JDK动态代理所代理的对象必须要实现一个接口)和CGLIB的动态代理,Hibernate的懒加载采用的是CGLIB的动态代理,CGLIB的动态代理可以生成目标类的子类,这也就是为什么创建对象关系映射的时候要求实体类不能够为final类型的原因了。


4、Hibernate懒加载(lazy)在何处使用?

  • <class>标签上,可以取值有true、false(默认为true)
  • <property>标签上,可以取值有true、false
  • <set>、<list>集合上,可以取值true、false、extra(默认为true)
  • <one-to-one>、<many-to-one>单端关联上,可以取值:false/proxy/no-proxy

二、get()和load()的懒加载:


实例一:

get()方法不支持懒加载

@Testpublic void get1() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();//执行此语句,立即加载,发出sql语句TBook book = (TBook) session.get(TBook.class, 1);System.out.println("书名:" + book.getBName());tran.commit();} catch (Exception e) {tran.rollback();e.printStackTrace();} finally {SessionUtil.close(session);}}

示例二:

load()方法支持懒加载(默认<class lazy="true">)

@Testpublic void load1() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();//执行此语句不会发出sql,只会返回一个代理对象TBook book = (TBook) session.load(TBook.class, 1);//不会发出sql语句,使用使用输入的1System.out.println("book.getId():"+book.getId());//真正使用数据时,发出sql语句System.out.println("书名:"+book.getBName());} catch (Exception e) {tran.rollback();e.printStackTrace();} finally {SessionUtil.close(session);}}

示例三:

load()方法支持懒加载(默认<class lazy="true">),提前关闭session

@Testpublic void load2(){Session session = null;try{session = SessionUtil.getSession();TBook book = (TBook)session.load(TBook.class, 1);//提前关闭sessionSessionUtil.close(session);//不能正确输出,抛出了LazyInitalizationException异常//could not initialize proxy - no SessionSystem.out.println("书名:" + book.getBName());}catch(Exception e){e.printStackTrace();}finally{SessionUtil.close(session);}}


三、关联映射中集合set和list中的lazy属性

示例一:

集合上的lazy=true(默认),其它默认。

@Testpublic void testLoad1() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();// 不发出sql,因为load对于实体默认懒加载Category c = (Category) session.load(Category.class, 1);// 发出sql,因为使用了该对象System.out.println("分类名称:" + c.getCategory());// 不发出sql,因为集合是懒加载,返回一个代理类。Set<TBook> tBooks = c.getTBooks();// 发出sql,因为使用了对象Iterator<TBook> it = tBooks.iterator();while(it.hasNext()){System.out.println(it.next().getBName());}tran.commit();} catch (Exception e) {e.printStackTrace();} finally {SessionUtil.close(session);}}

示例二:

集合上的lazy=true(默认),其他默认。

@Testpublic void testLoad1() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();// 不发出sql,因为load对于实体默认懒加载Category c = (Category) session.load(Category.class, 1);// 发出sql,因为使用了该对象System.out.println("分类名称:" + c.getCategory());// 不发出sql,因为集合是懒加载,返回一个代理类。Set<TBook> tBooks = c.getTBooks();// 发出sql,发出查询全部字段的sql,效率不高System.out.println("该类别图书数量"+tBooks.size());tran.commit();} catch (Exception e) {e.printStackTrace();} finally {SessionUtil.close(session);}}

实例三:

集合上的lazy=false,其他默认。

@Testpublic void testLoad1() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();// 不发出sql,因为load对于实体默认懒加载Category c = (Category) session.load(Category.class, 1);// 发出两条sql,分别加载Category和TBook//并且把集合中的数据也加载上来(虽然并没有使用集合中的对象),因为设置了集合的lazy=falseSystem.out.println("分类名称:" + c.getCategory());// 不发出sql,已经在前面加载了数据Set<TBook> tBooks = c.getTBooks();//不发出sql,前面已经加载了数据Iterator<TBook> it = tBooks.iterator();while(it.hasNext()){System.out.println(it.next().getBName());}System.out.println("该类别图书数量"+tBooks.size());tran.commit();} catch (Exception e) {e.printStackTrace();} finally {SessionUtil.close(session);}}

实例四:

集合上的lazy=false,其它默认。

@Testpublic void testLoad1() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();// 不发出sql,因为load对于实体默认懒加载Category c = (Category) session.load(Category.class, 1);// 发出两条sql,分别加载Category和TBook//并且把集合中的数据也加载上来(虽然并没有使用集合中的对象),因为设置了集合的lazy=falseSystem.out.println("分类名称:" + c.getCategory());// 不发出sql,已经在前面加载了数据Set<TBook> tBooks = c.getTBooks();//不发出sql,前面已经加载了数据System.out.println(tBooks.size());} catch (Exception e) {e.printStackTrace();} finally {SessionUtil.close(session);}}

示例五:

集合上的lazy=extra,其它默认

@Testpublic void testLoad1() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();// 不发出sql,因为load对于实体默认懒加载Category c = (Category) session.load(Category.class, 1);//会发出sqlSystem.out.println("分类名称:" + c.getCategory());// 不发出sql,只返回代理对象Set<TBook> tBooks = c.getTBooks();//会发出sqlIterator<TBook> iterator = tBooks.iterator();} catch (Exception e) {e.printStackTrace();} finally {SessionUtil.close(session);}}

示例六:

集合上的lazy=extra,其它默认。

@Testpublic void testLoad1() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();// 不发出sql,因为load对于实体默认懒加载Category c = (Category) session.load(Category.class, 1);//会发出sqlSystem.out.println("分类名称:" + c.getCategory());// 不发出sql,只返回代理对象Set<TBook> tBooks = c.getTBooks();//会发出sql,发出一条比较智能的sql//(select count(id) from admindb.t_book where category_Id =?)System.out.println(tBooks.size());} catch (Exception e) {e.printStackTrace();} finally {SessionUtil.close(session);}}

四、<one-to-one>、<many-to-one>单端关联上的lazy(懒加载)属性

示例一:

所有的lazy属性默认(支持懒加载)

@Testpublic void testLoad() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();//不发出sqlTBook b = (TBook) session.load(TBook.class, 1);//发出sql,只加载TBook,不会加载CategorySystem.out.println("图书名称:" + b.getBName());//不发出sql,返回代理对象Category category = b.getCategory();//真正使用对象时,发出sqlSystem.out.println("分类名称:" + category.getCategory());tran.commit();} catch (Exception e) {e.printStackTrace();} finally {SessionUtil.close(session);}}

示例二:

将<many-to-one>中lazy属性设为false,其它默认。

@Testpublic void testLoad() {Session session = null;Transaction tran = null;try {session = SessionUtil.getSession();tran = session.beginTransaction();//不发出sqlTBook b = (TBook) session.load(TBook.class, 1);//发出两条sql,分别是TBook和CategorySystem.out.println("图书名称:" + b.getBName());//不发出sql,上面已经加载数据Category category = b.getCategory();//不发出sql,上面已经加载数据System.out.println("分类名称:" + category.getCategory());tran.commit();} catch (Exception e) {e.printStackTrace();} finally {SessionUtil.close(session);}}








原创粉丝点击