本文共 14500 字,大约阅读时间需要 48 分钟。
hibernate的加载策略有两种:
1)即时加载:get加载
使用get加载数据,会立即查找,先到缓存中找,找不到再去数据库中找。
2)延迟加载(也叫懒加载lazy):laod加载
不会立即查找,当需要的时候才会查找。
容易造成异常:org.hibernate.LazyInitializationException: could not initialize proxy - no Session at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165) at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185) at com.myeclipse.pojo.Book_$$_jvstdc3_0.getName(Book_$$_jvstdc3_0.java) at com.ghibernate.test.HibernateTest.testLoad(HibernateTest.java:106) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
如果出现上面这个异常,大部分是因为session被关闭了,还要从session中取数据造成的。
但是懒加载也有优势:那就是效率高,因为
3)class的lazy
class默认情况下是支持懒加载的(在*.hbm.xml中的class中有一个属性lazy=“true”),所以在load方法时,是懒加载,但是当我们把lazy=“false”时,就不支持懒加载了,这是即使是使用load方法,也会是即时加载。
项目结构如下:
jar包和hibernate官网配置参见《》
Book实体类代码:
package com.myeclipse.pojo;import java.util.Date;public class Book { private int id; private String author; private String name; private double price; private Date pubDate; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Date getPubDate() { return pubDate; } public void setPubDate(Date pubDate) { this.pubDate = pubDate; } @Override public String toString() { return "Book [id=" + id + ", author=" + author + ", name=" + name + ", price=" + price + ", pubDate=" + pubDate + "]"; } }Book.hbm.xml代码:
HibernateUtil代码:
package com.robert.util;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.boot.registry.StandardServiceRegistryBuilder;import org.hibernate.cfg.Configuration;/** * hibernate工具类 */public class HibernateUtil { private static Configuration cfg = null; private static SessionFactory factory = null; private static Session session = null ; static { init(); } /** * 初始化获得Configuration和SessionFacroty对象 */ public static void init() { cfg = new Configuration().configure(); factory = cfg.buildSessionFactory(new StandardServiceRegistryBuilder() .applySettings(cfg.getProperties()).build()); } /** * 获得Session对象 * @return */ public static Session getSession() { if (factory != null){ return session = factory.openSession(); } init(); return session = factory.openSession(); } /** * 关闭Session */ public static void closeSession() { if(session!=null && session.isOpen()) session.close(); }}hibernate.cfg.xml代码:
com.mysql.jdbc.Driver jdbc:mysql:///hibernate4 root root org.hibernate.dialect.MySQL5Dialect true true update
HibernateTest代码:
package com.ghibernate.test;import java.util.Date;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.Test;import com.myeclipse.pojo.Book;import com.robert.util.HibernateUtil;public class HibernateTest { @Test public void testCreateDB() { Configuration cfg = new Configuration().configure(); SchemaExport se = new SchemaExport(cfg); // 第一个参数:是否生成ddl脚本 // 第二个参数:是否执行到数据库中 se.create(true, true); } @Test public void testSave() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Book book = new Book(); book.setName("读者"); book.setPrice(5.6); book.setAuthor("众人"); book.setPubDate(new Date()); Book book1 = new Book(); book1.setName("傲慢与偏见"); book1.setPrice(80.0); book1.setAuthor("简.奥斯汀"); book1.setPubDate(new Date()); Book book2 = new Book(); book2.setName("中国历史"); book2.setPrice(30.0); book2.setAuthor("人民出版社"); book2.setPubDate(new Date()); Book book3 = new Book(); book3.setName("翩眇之旅"); book3.setPrice(70.0); book3.setAuthor("萧鼎"); book3.setPubDate(new Date()); Book book4 = new Book(); book4.setName("蓝血人"); book4.setPrice(60.0); book4.setAuthor("卫斯理"); book4.setPubDate(new Date()); Book book5 = new Book(); book5.setName("我的大学"); book5.setPrice(60.5); book5.setAuthor("高尔基"); book5.setPubDate(new Date()); session.save(book); session.save(book1); session.save(book2); session.save(book3); session.save(book4); session.save(book5); tx.commit(); HibernateUtil.closeSession(); } @Test public void testGet() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Book book = (Book) session.get(Book.class, 1); System.out.println("book_name=" + book.getName()); tx.commit(); HibernateUtil.closeSession(); System.out.println("book_name=" + book.getName()); } @Test public void testLoad() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Book book = (Book) session.load(Book.class, 1); System.out.println("book_id=" + book.getId()); tx.commit(); HibernateUtil.closeSession(); //当Book.hbm.xml中的class中的lazy参数是ture时,这里会报错,错误见博客开头 System.out.println("book_name=" + book.getName()); }}
=========================================================================
还有一种情况是get的懒加载,如下:
新建一个项目,结构如下:
hibernate项目搭建,参见《》
实体类Book如下:
package com.myeclipse.pojo;import java.util.Date;public class Book { private int id; private String author; private String name; private double price; private Date pubDate; private Category category; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Date getPubDate() { return pubDate; } public void setPubDate(Date pubDate) { this.pubDate = pubDate; } public Category getCategory() { return category; } public void setCategory(Category category) { this.category = category; } @Override public String toString() { return "Book [id=" + id + ", author=" + author + ", name=" + name + ", price=" + price + ", pubDate=" + pubDate + "]"; } }
Book.hbm.xml代码:
Category实体类代码:
package com.myeclipse.pojo;import java.util.HashSet;import java.util.Set;public class Category{ private int id; private String name; private Setbooks = new HashSet (); public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set getBooks() { return books; } public void setBooks(Set books) { this.books = books; }}
Category.hbm.xml代码:
HIbernateUtil和hibernate.cfg.xml和上面一样。
HibernateTest代码:
package com.ghibernate.test;import java.util.Date;import java.util.Iterator;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.Test;import com.myeclipse.pojo.Book;import com.myeclipse.pojo.Category;import com.robert.util.HibernateUtil;public class HibernateTest { @Test public void testCreateDB() { Configuration cfg = new Configuration().configure(); SchemaExport se = new SchemaExport(cfg); // 第一个参数:是否生成ddl脚本 // 第二个参数:是否执行到数据库中 se.create(true, true); } @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(); } @Test public void testGet() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); //当Category.hbm.xml中的set中的lazy属性是true(默认是true)时,先查询一端的Category,只会先查询Category数据, //当执行下面for中的category.getBooks时才会去查询Book数据,这时就是懒加载 //但是当我们把Category.hbm.xml中的set中的lazy属性改为false时,会在查询Category的时候,把Book也查询出来,这时就是即时加载 Category category = (Category) session.get(Category.class, 1) ; System.out.println("category_name="+category.getName()); for (Iteratoriter = category.getBooks().iterator();iter.hasNext();) { System.out.println(iter.next().getName()); } tx.commit(); HibernateUtil.closeSession(); } }
在HibernateTest类中增加一个方法
@Test public void testLoad() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Category category = (Category) session.load(Category.class, 1) ; System.out.println("category_name="+category.getName()); System.out.println("书籍数量:"+category.getBooks().size()); tx.commit(); HibernateUtil.closeSession(); }断点运行,可以看到,执行完
Category category = (Category) session.load(Category.class, 1) ;
这句,并没有查询数据的sql语句
当执行
System.out.println("category_name="+category.getName());这句后,打印sql语句如下:
Hibernate: select category0_.id as id1_0_0_, category0_.name as name2_0_0_ from Category category0_ where category0_.id=?category_name=文学
继续运行
System.out.println("书籍数量:"+category.getBooks().size());
这句后,打印sql语句
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当把Category.hbm.xml中set的lazy更改为extra时,代码如下:
HibernateTest中的testLoad代码:
@Test public void testLoad() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Category category = (Category) session.load(Category.class, 1) ; System.out.println("category_name="+category.getName()); System.out.println("书籍数量:"+category.getBooks().size()); 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 count(id) from t_book where category_id =?书籍数量:24)总结:
set和list默认下都是lazy=true,默认支持懒加载。但是当使用size()的时候,依然会查询整个set集合的内容。
lazy=false时,立即查询所有集合的内容。
lazy=extra时,比较智能,支持懒加载,当使用size()的时候,不会查询整个集合,仅仅查询集合中元素的个数,当需要使用集合元素的内容时,再去查询。
5)单端关联上的lazy:(many-to-one,one-to-one),默认是支持懒加载的lazy=proxy
6)property上的懒加载lazy,需要用到第三方增加,且大部分情况下用不到property懒加载,只有当是大对象时Blob,Clob才会用到