标签(空格分隔): 后端技术学习
前言
在hibernate的使用中,为了减少对数据库的访问,对于存在关联关系映射表使用的时候,我们可以使用懒加载的方式,让hibernate帮我查询单个对象信息的同时,暂缓查询它所关联的另一些对象的信息,当我们真正的使用它所管理的对象的时候后再帮我们查询关联对象。同时懒加载的方式也是hibernate为我们默认选择的方式。虽然懒加载为我们带来了减少数据库查询的好处,但是在使用的过程中如果是对hibernate理解不够容易出现难以寻找的问题。
引入
在课堂上老师引导我们,了解hibernate的查询方式的时候,介绍了使用懒加载的时候session.load()查询会返回的内容并不是我们真正的POJO实体对象,实际上返回的是实体对象的代理类。它跟能够在我调用POJO的getXX()方法的时候使用代理的方式帮我们进行数据库的查询实现懒加载,然后返回我们需要查寻得关联对象。接下来我们细细理解一下半深入懒加载与懒加载代理类。
session.load()讲解
API指出 session.load()
查询总是返回一个并非直接对应数据库行的假对象(代理类)。查出来的假对象它所有的属性也没有被正式的初始化。对它所有的操作,直到事务提交时才进行对它之前所有操作的合并,然后执行数据库语句。
同时在事务提交的时候,如果数据库中原本并没有假对象对应的行则会抛出ObjectNotFoundException
。
如果是没有使用事务load()查询,则在进行session.save(“假对象”),session.saveOrUpdate(“假对象”)的时候则会提示org.hibernate.PersistentObjectException: uninitialized proxy passed to save()
的异常。原因仍然假对象(代理类)懒加载。
例如 session.load()
coderInput
Stock stock = (Stock)session.load(Stock.class, new Integer(2));
StockTransaction stockTransactions = new StockTransaction();
//set stockTransactions detail
stockTransactions.setStock(stock);
session.save(stockTransactions);
Output
Hibernate:
insert into mkyong.stock_transaction (...)
values (?, ?, ?, ?, ?, ?)
注意:实际上并不是
session.load()
的所有查询都返回的是POJO实体对象的代理类,只有在POJO对象的映射文件*.hbm.xml中指定了懒加载(即没有设置lazy="false"
)的时候才会返回POJO实体对象的代理类。否则不是代理类。
session.get讲解
相对于session.load()
,session.get()
就非常直接,使用它的每一次查询操作返回的都是对应着数据库中的真实对象,这个对象代表的是数据库中真实的一行,也不是代理类。
真是因为这个原因session.get()
的查询它是不支持懒加载的。如果查询的类有关联对象,它会同时将关联对象统统查出来。
如果在数据库的查询中找不到对应搜索条件的行则返回null,通过由于在session.get()
返回的不是代理类,在session.close()
后它不会被销毁,不会为空。
例如 session.get()
codeInput
Stock stock = (Stock)session.get(Stock.class, new Integer(2));
StockTransaction stockTransactions = new StockTransaction();
//set stockTransactions detail
stockTransactions.setStock(stock);
session.save(stockTransactions);
Output
Hibernate:
select ... from mkyong.stock stock0_
where stock0_.STOCK_ID=?
Hibernate:
insert into mkyong.stock_transaction (...)
values (?, ?, ?, ?, ?, ?)
代理类
代理类是通过动态代理的方式创建,是由Hibernate框架帮我们创建的,这也是Hibernate框架的面相切面的特点。Hibernate在通过*.hbm.xml文件帮我们让数据库和正真实体之间建立联系,同时又为我们提供了关联关系映射的功能。在使用懒加载模式下的时候使用session.load
等查询的时候,会返回给我们一个代理类。代理类的所有属性都会在真正使用的时候才会去加载。如果仅仅只是执行了查询语句,没有任何的修改访问操作,实际上最后的事务提交时Hibernate是没有进行数据库查询的。
同时非常重要的一点是Hibernate的会在代理类相关联session关闭的时候,会同时销毁代理类。也就是说如果你所使用的引用是代理类,你执行了session.close()
,你再去访问这个代理类就会的到这样的org.hibernate.LazyInitializationException: could not initialize proxy - no Session
报错提示。
但是如果是使用的session.get(),或者是关闭了懒加载则不会使用到代理类,不会出现上述问题。同时也享受不到Hibernate智能的数据库优化。