本文共 17489 字,大约阅读时间需要 58 分钟。
抓取策略(fetching strategy)是指:当应用程序需要在(Hibernate实体对象图的)关联关系间经行导航的时候,hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或条件查询(Criteria Query)
中重载声明。
Hibernate3 定义了如下几种抓取策略:
连接抓取(Join fetching) - Hibernate通过 在SELECT
语句使用OUTER JOIN
(外连接)来 获得对象的关联实例或者关联集合,这种情况lazy无效。
查询抓取(Select fetching) - 另外发送一条SELECT
语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"
禁止 延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
子查询抓取(Subselect fetching) - 另外发送一条SELECT
语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false"
禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
批量抓取(Batch fetching) - 对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条SELECT
语句获取一批对象实例或集合。
下面来分别介绍这几种抓取
项目结构如图
所有的代码和上一节《》中的代码一样,可以参考,
现在多的一端设置fetch
Book.hbm.xml代码:
Category.hbm.xml代码:
HibernateTest中TestCreateDB代码:
@Test public void testCreateDB() { Configuration cfg = new Configuration().configure(); SchemaExport se = new SchemaExport(cfg); // 第一个参数:是否生成ddl脚本 // 第二个参数:是否执行到数据库中 se.create(true, true); }使用Junit4执行,重新生成数据库表。
控制台打印的sql语句如下:
alter table t_book drop foreign key FK_cm584cq6cv5yht4jrqal0ocaq drop table if exists Category drop table if exists t_book create table Category ( id integer not null auto_increment, name varchar(255), primary key (id) ) create table t_book ( id integer not null auto_increment, category_id integer, author varchar(255), book_name varchar(255), price double precision, pubDate datetime, primary key (id) ) alter table t_book add constraint FK_cm584cq6cv5yht4jrqal0ocaq foreign key (category_id) references Category (id)
HibernateTest类中的TestSave()方法代码:
/** * 保存数据 */ @Test public void testSave() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Category category = new Category(); category.setName("文学"); Category category1 = new Category(); category1.setName("历史"); Category category2 = new Category(); category2.setName("仙侠"); Category category3 = new Category(); category3.setName("科幻"); Category category4 = new Category(); category4.setName("恐怖"); Book book = new Book(); book.setName("读者"); book.setPrice(5.6); book.setAuthor("众人"); book.setPubDate(new Date()); book.setCategory(category); Book book1 = new Book(); book1.setName("傲慢与偏见"); book1.setPrice(80.0); book1.setAuthor("简.奥斯汀"); book1.setPubDate(new Date()); book1.setCategory(category1); Book book2 = new Book(); book2.setName("中国历史"); book2.setPrice(30.0); book2.setAuthor("人民出版社"); book2.setPubDate(new Date()); book2.setCategory(category1); Book book3 = new Book(); book3.setName("翩眇之旅"); book3.setPrice(70.0); book3.setAuthor("萧鼎"); book3.setPubDate(new Date()); book3.setCategory(category2); Book book4 = new Book(); book4.setName("蓝血人"); book4.setPrice(60.0); book4.setAuthor("卫斯理"); book4.setPubDate(new Date()); book4.setCategory(category3); Book book5 = new Book(); book5.setName("我的大学"); book5.setPrice(60.5); book5.setAuthor("高尔基"); book5.setPubDate(new Date()); book5.setCategory(category); session.save(book); session.save(book1); session.save(book2); session.save(book3); session.save(book4); session.save(book5); session.save(category4); tx.commit(); HibernateUtil.closeSession(); }
执行保存数据,sql语句如下:
Hibernate: insert into Category (name) values (?)Hibernate: insert into t_book (category_id, author, book_name, price, pubDate) values (?, ?, ?, ?, ?)Hibernate: insert into Category (name) values (?)Hibernate: insert into t_book (category_id, author, book_name, price, pubDate) values (?, ?, ?, ?, ?)Hibernate: insert into t_book (category_id, author, book_name, price, pubDate) values (?, ?, ?, ?, ?)Hibernate: insert into Category (name) values (?)Hibernate: insert into t_book (category_id, author, book_name, price, pubDate) values (?, ?, ?, ?, ?)Hibernate: insert into Category (name) values (?)Hibernate: insert into t_book (category_id, author, book_name, price, pubDate) values (?, ?, ?, ?, ?)Hibernate: insert into t_book (category_id, author, book_name, price, pubDate) values (?, ?, ?, ?, ?)Hibernate: insert into Category (name) values (?)数据库表中的数据如图:
HibernateTest类中的查询代码如下:
/** * 查询图书 */ @Test public void testLoadBook() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Book book = (Book) session.load(Book.class, 1) ; System.out.println("-------------------------"); System.out.println("bookName = "+book.getName()); System.out.println("==========================="); System.out.println("categoryName = "+book.getCategory().getName()); tx.commit(); HibernateUtil.closeSession(); }打印的sql语句如下:
INFO: HHH000232: Schema update complete-------------------------Hibernate: select book0_.id as id1_1_0_, book0_.category_id as category2_1_0_, book0_.author as author3_1_0_, book0_.book_name as book_nam4_1_0_, book0_.price as price5_1_0_, book0_.pubDate as pubDate6_1_0_ from t_book book0_ where book0_.id=?Hibernate: select category0_.id as id1_0_0_, category0_.name as name2_0_0_ from Category category0_ where category0_.id=?bookName = 读者===========================categoryName = 文学从sql语句可以看出,
当执行Book book = (Book) session.load(Book.class, 1) ;这句话时,并没有打印sql语句,
当查询book.getName(),图书的Name时,打印了查询sql语句:
Hibernate: select book0_.id as id1_1_0_, book0_.category_id as category2_1_0_, book0_.author as author3_1_0_, book0_.book_name as book_nam4_1_0_, book0_.price as price5_1_0_, book0_.pubDate as pubDate6_1_0_ from t_book book0_ where book0_.id=?Hibernate: select category0_.id as id1_0_0_, category0_.name as name2_0_0_ from Category category0_ where category0_.id=?
这两条sql语句可以看出,先根据book的id 查询了t_book表,t_book表中有category_id,又根据category_id查询了Category表。
当我们把Book.hbm.xml中的lazy改成proxy时,如图:
执行TestLoadBook()方法,打印的sql语句,如下:
-------------------------Hibernate: select book0_.id as id1_1_0_, book0_.category_id as category2_1_0_, book0_.author as author3_1_0_, book0_.book_name as book_nam4_1_0_, book0_.price as price5_1_0_, book0_.pubDate as pubDate6_1_0_ from t_book book0_ where book0_.id=?bookName = 读者===========================Hibernate: select category0_.id as id1_0_0_, category0_.name as name2_0_0_ from Category category0_ where category0_.id=?categoryName = 文学此时当需要获取对应的数据时,才会执行相应的sql语句。
下面在一的一端设置fetch
Category.hbm.xml代码如下:
fetch设置为select,
testGetCategory()方法的代码如下:
@Test public void testGetCategory() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Category category = (Category) session.get(Category.class, 1); System.out.println("---------------------------------------------"); System.out.println("category_name=" + category.getName()); System.out.println("============================================"); for (Iteratoriter = category.getBooks().iterator(); iter .hasNext();) { System.out.println(iter.next().getName()); } tx.commit(); HibernateUtil.closeSession(); }
打印的sql语句如下:
Hibernate: select category0_.id as id1_0_0_, category0_.name as name2_0_0_ from Category category0_ where category0_.id=?---------------------------------------------category_name=文学============================================Hibernate: select books0_.category_id as category2_0_0_, books0_.id as id1_1_0_, books0_.id as id1_1_1_, books0_.category_id as category2_1_1_, books0_.author as author3_1_1_, books0_.book_name as book_nam4_1_1_, books0_.price as price5_1_1_, books0_.pubDate as pubDate6_1_1_ from t_book books0_ where books0_.category_id=?我的大学读者
从上面可以看出来,get方法,当时就查询了Category表的sql语句,当需要查询Book的数据时,才会执行t_book的数据库表信息。
先说多段的Book
Book.hbm.xml代码:
fetch是join,lazy是proxy
HIbernateTest类中的testLoadBook()方法,代码:
/** * 查询图书 */ @Test public void testLoadBook() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Book book = (Book) session.load(Book.class, 1); System.out.println("-------------------------"); System.out.println("bookName = " + book.getName()); System.out.println("==========================="); System.out.println("categoryName = " + book.getCategory().getName()); tx.commit(); HibernateUtil.closeSession(); }
控制台打印的sql语句是:
INFO: HHH000232: Schema update complete-------------------------Hibernate: select book0_.id as id1_1_0_, book0_.category_id as category2_1_0_, book0_.author as author3_1_0_, book0_.book_name as book_nam4_1_0_, book0_.price as price5_1_0_, book0_.pubDate as pubDate6_1_0_, category1_.id as id1_0_1_, category1_.name as name2_0_1_ from t_book book0_ left outer join Category category1_ on book0_.category_id=category1_.id where book0_.id=?bookName = 读者===========================categoryName = 文学
由上面可以看到,在需要book的信息时,sql语句使用 left outer join 把Category表中的信息也查询了出来。
下面从一的一端Category来查询
HibernateTest类中的testGetCategory()方法代码:
@Test public void testGetCategory() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Category category = (Category) session.get(Category.class, 1); System.out.println("---------------------------------------------"); System.out.println("category_name=" + category.getName()); System.out.println("============================================"); for (Iteratoriter = category.getBooks().iterator(); iter .hasNext();) { System.out.println(iter.next().getName()); } tx.commit(); HibernateUtil.closeSession(); }
控制台打印的sql语句如下:
Hibernate: select category0_.id as id1_0_0_, category0_.name as name2_0_0_, books1_.category_id as category2_0_1_, books1_.id as id1_1_1_, books1_.id as id1_1_2_, books1_.category_id as category2_1_2_, books1_.author as author3_1_2_, books1_.book_name as book_nam4_1_2_, books1_.price as price5_1_2_, books1_.pubDate as pubDate6_1_2_ from Category category0_ left outer join t_book books1_ on category0_.id=books1_.category_id where category0_.id=?---------------------------------------------category_name=文学============================================读者我的大学从一的一端也是从使用left outer join 方法把t_book表的数据一起查询了出来
接下来我们把Category.hbm.xml和Book.hbm.xml中的lazy和fetch都去掉,执行testLoad()方法,代码如下:
@Test public void testLoad() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Listlist = session.createCriteria(Category.class).list() ; System.out.println("---------------------------------"); System.out.println("类型个数:"+list.size()); for (Category category : list) { System.out.println("================================"); System.out.println(category.getName()+"----数据本书:"+category.getBooks().size()); } tx.commit(); HibernateUtil.closeSession(); }
执行后,打印的sql语句如下:
Hibernate: select this_.id as id1_0_0_, this_.name as name2_0_0_ from Category this_---------------------------------类型个数:5================================Hibernate: select books0_.category_id as category2_0_0_, books0_.id as id1_1_0_, books0_.id as id1_1_1_, books0_.category_id as category2_1_1_, books0_.author as author3_1_1_, books0_.book_name as book_nam4_1_1_, books0_.price as price5_1_1_, books0_.pubDate as pubDate6_1_1_ from t_book books0_ where books0_.category_id=?文学----数据本书:2================================Hibernate: select books0_.category_id as category2_0_0_, books0_.id as id1_1_0_, books0_.id as id1_1_1_, books0_.category_id as category2_1_1_, books0_.author as author3_1_1_, books0_.book_name as book_nam4_1_1_, books0_.price as price5_1_1_, books0_.pubDate as pubDate6_1_1_ from t_book books0_ where books0_.category_id=?历史----数据本书:2================================Hibernate: select books0_.category_id as category2_0_0_, books0_.id as id1_1_0_, books0_.id as id1_1_1_, books0_.category_id as category2_1_1_, books0_.author as author3_1_1_, books0_.book_name as book_nam4_1_1_, books0_.price as price5_1_1_, books0_.pubDate as pubDate6_1_1_ from t_book books0_ where books0_.category_id=?仙侠----数据本书:1================================Hibernate: select books0_.category_id as category2_0_0_, books0_.id as id1_1_0_, books0_.id as id1_1_1_, books0_.category_id as category2_1_1_, books0_.author as author3_1_1_, books0_.book_name as book_nam4_1_1_, books0_.price as price5_1_1_, books0_.pubDate as pubDate6_1_1_ from t_book books0_ where books0_.category_id=?科幻----数据本书:1================================Hibernate: select books0_.category_id as category2_0_0_, books0_.id as id1_1_0_, books0_.id as id1_1_1_, books0_.category_id as category2_1_1_, books0_.author as author3_1_1_, books0_.book_name as book_nam4_1_1_, books0_.price as price5_1_1_, books0_.pubDate as pubDate6_1_1_ from t_book books0_ where books0_.category_id=?恐怖----数据本书:0
接下来我们在Category.hbm.xml代码中,加入fetch=“subselect” ,如图:
继续testLoad()方法,打印的sql语句如下:
Hibernate: select this_.id as id1_0_0_, this_.name as name2_0_0_ from Category this_---------------------------------类型个数:5================================Hibernate: select books0_.category_id as category2_0_1_, books0_.id as id1_1_1_, books0_.id as id1_1_0_, books0_.category_id as category2_1_0_, books0_.author as author3_1_0_, books0_.book_name as book_nam4_1_0_, books0_.price as price5_1_0_, books0_.pubDate as pubDate6_1_0_ from t_book books0_ where books0_.category_id in ( select this_.id from Category this_ )文学----数据本书:2================================历史----数据本书:2================================仙侠----数据本书:1================================科幻----数据本书:1================================恐怖----数据本书:0
由sql语句可以看出,当我们需要查询t_book数据时,sql语句的where语句是:
where books0_.category_id in ( select this_.id from Category this_ )
一次性将所有的分类Category数据全部查询出来。
假设现在我想查询Category的id是1,3,5的数据,那么方法testLoadWhere代码是:
@Test public void testLoadWhere() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); List控制台打印的sql语句如下:list = session.createCriteria(Category.class) .add(Restrictions.in("id", new Integer[]{1,3,5})) .list() ; System.out.println("---------------------------------"); System.out.println("类型个数:"+list.size()); for (Category category : list) { System.out.println("================================"); System.out.println(category.getName()+"----数据本书:"+category.getBooks().size()); } tx.commit(); HibernateUtil.closeSession(); }
Hibernate: select this_.id as id1_0_0_, this_.name as name2_0_0_ from Category this_ where this_.id in ( ?, ?, ? )---------------------------------类型个数:3================================Hibernate: select books0_.category_id as category2_0_1_, books0_.id as id1_1_1_, books0_.id as id1_1_0_, books0_.category_id as category2_1_0_, books0_.author as author3_1_0_, books0_.book_name as book_nam4_1_0_, books0_.price as price5_1_0_, books0_.pubDate as pubDate6_1_0_ from t_book books0_ where books0_.category_id in ( select this_.id from Category this_ where this_.id in ( ?, ?, ? ) )文学----数据本书:2================================仙侠----数据本书:1================================恐怖----数据本书:0
Book.hbm.xml代码修改为:
上面的代码中增加了一个batch-size属性,如图: