很多时候你会发现,使用Hibernate的开发人员会混淆session.get()和session.load()的用法,你是否理解这两个方法的区别并知道在什么时候使用正确的方法呢?
实际上,两个方法都是用来从数据库获取对象,只不过实现机制不一样而已。
1. session.load()
- 这种方式总是会返回一个代理而不是真正得去查询数据库。 在Hibernate里面,代理是一个依据ID值获取到的对象,该对象的属性还没有初始化,它看起来就是一个临时的虚拟对象而已。
- 如果load方法没有找到数据,就会抛出ObjectNotFoundException.
2. session.get()
- 这种方式总是会去数据库查询数据并返回一个真实的对象,该对象就代表数据库中的一行而非代理。
- 如果没有找到数据就会返回null.
性能方面的区别
由于某些原因,Hibernate会创建一些对象,当你做关联查询的时候,为了维护对象之间的关系,一般来说你会从数据库中拿到一个对象(持久化的实例)并把该对象作为一个引用指向另一个对象。我们来看一个例子来让大家理解什么情况下我们应该使用session.load().
1. session.get()
拿一个股票的应用来说,股票跟股票交易之间应该是一对多的关系,当你保存一次股票交易的时候,一般来说我们会写如下的代码:
Stock stock = (Stock)session.get(Stock.class, new Integer(2)); StockTransaction stockTransactions = new StockTransaction(); //set stockTransactions detail stockTransactions.setStock(stock); session.save(stockTransactions);
输出:
Hibernate: select ... from mkyong.stock stock0_ where stock0_.STOCK_ID=? Hibernate: insert into mkyong.stock_transaction (...) values (?, ?, ?, ?, ?, ?)
用session.get(), Hibernate会查询数据库以获取Stock对象,并把该对象作为一个引用指向StockTransaction对象。然而,保存流程数据的操作是很耗费资源的,如果一个小时内有成千上万次股票交易,你认为有必要每次都去查询数据库,去首先拿到Stock的真实对象然后把StockTransaction保存到数据库中吗?毕竟来说,你只是需要一个Stock的对象来让StockTransaction引用而已。
2. session.load()
在上面的应用场景中,session.load()会是一个好的解决方案,让我们来看一个例子:
Stock stock = (Stock)session.load(Stock.class, new Integer(2)); StockTransaction stockTransactions = new StockTransaction(); //set stockTransactions detail stockTransactions.setStock(stock); session.save(stockTransactions);
输出:
Hibernate: insert into mkyong.stock_transaction (...) values (?, ?, ?, ?, ?, ?)
使用session.load()方式,Hibernate不会查询数据库(输出的SQL里面没有select语句)来获取Stock对象,这种方式会返回一个Stock的代理对象 - 一个依据给定的ID值得虚假对象。这这种场景中,一个代理对象就足够用来保存股票交易的记录了。
异常方面的区别
session.load()
Stock stock = (Stock)session.load(Stock.class, new Integer(100)); //proxy //initialize proxy, no row for id 100, throw ObjectNotFoundException System.out.println(stock.getStockCode());
load方法总是会依据给定的ID值来返回一个代理对象,哪怕这个ID值甚至都不存在于数据库。然而,当Hibernate试图从数据库中获取属性来初始化该代理对象的时候,它就会使用select语句来从数据库查询数据,如果没有找到任何数据行,就会抛出ObjectNotFoundException了
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.mkyong.common.Stock#100]
session.get()
//return null if not found Stock stock = (Stock)session.get(Stock.class, new Integer(100)); System.out.println(stock.getStockCode()); //java.lang.NullPointerException
与load方法不一样,如果在数据库中没有找到数据,get方法会返回null.
总结:
关于这两个方法的选择没有一成不变的解决方案,你必须要首先理解这两种方法的区别和联系,然后才能决定哪种方式更适合你的应用场景。
PS:第一次翻译国外网站的文章,感觉真是费力,本人英语水平有限,还请各位多多谅解。其实关于session.get()和session.load()的区别,只要记住两点就好了:
1. load方法支持延迟加载而get方法则不会。
2. load方法在没找到数据的时候会抛出ObjectNotFoundException而get方法则会返回空